├── .github └── workflows │ ├── gh-pages.yaml │ ├── nix.yaml │ └── test.yaml ├── .gitignore ├── Cargo.lock ├── Cargo.nix ├── Cargo.toml ├── LICENSE ├── README.md ├── clippy.toml ├── ferrite-demo ├── Cargo.toml └── src │ └── bin │ ├── channel.rs │ ├── concat.rs │ ├── custom_choice.rs │ ├── cut.rs │ ├── detach.rs │ ├── dining_philosophers.rs │ ├── external_choice.rs │ ├── hello.rs │ ├── internal_choice.rs │ ├── message.rs │ ├── nested_recursive.rs │ ├── pair.rs │ ├── queue.rs │ ├── restaurant.rs │ ├── shared.rs │ ├── shared_queue.rs │ ├── stream.rs │ └── wrap_stream.rs ├── ferrite-session ├── Cargo.toml └── src │ ├── internal │ ├── base │ │ ├── channel │ │ │ ├── functions.rs │ │ │ ├── impls.rs │ │ │ ├── mod.rs │ │ │ ├── traits.rs │ │ │ └── types.rs │ │ ├── context │ │ │ ├── impls.rs │ │ │ ├── mod.rs │ │ │ └── traits.rs │ │ ├── mod.rs │ │ ├── protocol │ │ │ ├── impls.rs │ │ │ ├── mod.rs │ │ │ ├── traits.rs │ │ │ └── types.rs │ │ ├── public.rs │ │ ├── rec │ │ │ ├── functions.rs │ │ │ ├── impls.rs │ │ │ ├── mod.rs │ │ │ ├── traits.rs │ │ │ └── types.rs │ │ ├── session │ │ │ ├── functions.rs │ │ │ ├── mod.rs │ │ │ └── types.rs │ │ └── shared │ │ │ ├── functions.rs │ │ │ ├── mod.rs │ │ │ ├── serialize.rs │ │ │ └── types.rs │ ├── functional │ │ ├── base.rs │ │ ├── mod.rs │ │ ├── nat.rs │ │ ├── public.rs │ │ ├── row │ │ │ ├── impls.rs │ │ │ ├── mod.rs │ │ │ ├── structs.rs │ │ │ ├── traits.rs │ │ │ └── utils.rs │ │ └── type_app │ │ │ ├── impls.rs │ │ │ ├── mod.rs │ │ │ ├── structs.rs │ │ │ └── traits.rs │ ├── mod.rs │ ├── protocol │ │ ├── channel │ │ │ ├── mod.rs │ │ │ ├── receive.rs │ │ │ └── send.rs │ │ ├── choice │ │ │ ├── either.rs │ │ │ ├── external_choice.rs │ │ │ ├── internal_choice.rs │ │ │ └── mod.rs │ │ ├── end.rs │ │ ├── mod.rs │ │ ├── public.rs │ │ ├── shared │ │ │ ├── linear_to_shared.rs │ │ │ ├── lock.rs │ │ │ ├── mod.rs │ │ │ └── shared_to_linear.rs │ │ ├── value │ │ │ ├── mod.rs │ │ │ ├── receive.rs │ │ │ └── send.rs │ │ └── wrap.rs │ ├── public.rs │ └── session │ │ ├── apply.rs │ │ ├── channel │ │ ├── mod.rs │ │ ├── receive.rs │ │ └── send.rs │ │ ├── choice │ │ ├── external │ │ │ ├── choose.rs │ │ │ ├── mod.rs │ │ │ └── offer_choice.rs │ │ ├── internal │ │ │ ├── case.rs │ │ │ ├── mod.rs │ │ │ └── offer_case.rs │ │ ├── mod.rs │ │ └── run_cont.rs │ │ ├── context.rs │ │ ├── cut.rs │ │ ├── end.rs │ │ ├── fix.rs │ │ ├── forward.rs │ │ ├── include.rs │ │ ├── mod.rs │ │ ├── public.rs │ │ ├── run.rs │ │ ├── shared │ │ ├── accept.rs │ │ ├── acquire.rs │ │ ├── detach.rs │ │ ├── forward.rs │ │ ├── mod.rs │ │ └── release.rs │ │ ├── step.rs │ │ ├── value │ │ ├── mod.rs │ │ ├── receive.rs │ │ └── send.rs │ │ └── wrap.rs │ ├── lib.rs │ └── macros.rs ├── flake.lock ├── flake.nix ├── rust-toolchain.toml ├── rustfmt.toml └── scripts └── cachix.sh /.github/workflows/gh-pages.yaml: -------------------------------------------------------------------------------- 1 | name: GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - uses: actions-rs/toolchain@v1 15 | with: 16 | toolchain: stable 17 | 18 | - run: cargo doc 19 | 20 | - name: Deploy 21 | uses: peaceiris/actions-gh-pages@v3 22 | with: 23 | deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }} 24 | external_repository: maybevoid/ferrite-doc 25 | publish_dir: ./target/doc 26 | -------------------------------------------------------------------------------- /.github/workflows/nix.yaml: -------------------------------------------------------------------------------- 1 | name: Nix Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - uses: cachix/install-nix-action@v15 15 | with: 16 | nix_path: nixpkgs=channel:nixos-unstable 17 | 18 | - uses: cachix/cachix-action@v10 19 | with: 20 | name: maybevoid 21 | authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' 22 | 23 | - run: nix build 24 | 25 | - run: nix run 26 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Cargo Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - uses: actions-rs/toolchain@v1 15 | with: 16 | toolchain: stable 17 | 18 | - run: cargo build 19 | 20 | - run: cargo test 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | result* 3 | .vscode/ 4 | *.log 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ "ferrite-session", "ferrite-demo" ] 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 2019-2020 Soares Ruofei Chen 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ferrite - Session Types DSL for Rust 2 | 3 | [![Crates.io][crates-badge]][crates-url] 4 | [![Documentation][doc-badge]][doc-url] 5 | [![Apache licensed][license-badge]][license-url] 6 | [![Build Status][actions-badge]][actions-url] 7 | 8 | [crates-badge]: https://img.shields.io/crates/v/ferrite-session.svg 9 | [crates-url]: https://crates.io/crates/ferrite-session 10 | [doc-badge]: https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square 11 | [doc-url]: https://ferrite-rs.github.io/ferrite-doc/ferrite_session/ 12 | [license-badge]: https://img.shields.io/crates/l/ferrite-session.svg 13 | [license-url]: https://github.com/ferrite-rs/ferrite/blob/master/LICENSE 14 | [actions-badge]: https://github.com/ferrite-rs/ferrite/workflows/Cargo%20Tests/badge.svg 15 | [actions-url]: https://github.com/ferrite-rs/ferrite/actions 16 | 17 | ## Overview 18 | 19 | Ferrite is a DSL for writing session type programs in Rust. 20 | This is an ongoing research work by [Soares Chen](https://maybevoid.com/) 21 | and [Stephanie Balzer](http://www.cs.cmu.edu/~balzers/), and 22 | [Bernardo Toninho](http://ctp.di.fct.unl.pt/~btoninho/) to implement 23 | session types in Rust. 24 | 25 | ## Documentation 26 | 27 | - The paper _Ferrite: A Judgmental Embedding of Session Types in Rust_ 28 | is published at [ECOOP 2022](https://doi.org/10.4230/LIPIcs.ECOOP.2022.22). 29 | 30 | - A technical report for Ferrite is currently available at 31 | [Arxiv](https://arxiv.org/abs/2009.13619). 32 | 33 | - A work-in-progress documentation for Ferrite is available as a 34 | [book](http://ferrite-rs.github.io/ferrite-book/). 35 | 36 | ## Build Instructions 37 | 38 | ```bash 39 | cargo build 40 | ``` 41 | 42 | ## Running Demo 43 | 44 | A number of demo executables are available in the [`src/bin`](src/bin) directory. 45 | To run a particular demo, use `cargo run` with the name of the demo file. 46 | For example: 47 | 48 | ```bash 49 | RUST_LOG=info cargo run --bin hello 50 | RUST_LOG=info cargo run --bin shared 51 | ``` 52 | 53 | ## Acknowledgement 54 | 55 | This material is based upon work supported by the National Science Foundation under Grant No. CCF-1718267. 56 | Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) 57 | and do not necessarily reflect the views of the National Science Foundation. 58 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | blacklisted-names = [] 2 | type-complexity-threshold = 4096 3 | -------------------------------------------------------------------------------- /ferrite-demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ferrite-demo" 3 | version = "0.1.0" 4 | edition = "2018" 5 | description = "Session Types DSL for Rust (Demo)" 6 | homepage = "https://github.com/maybevoid/ferrite" 7 | repository = "https://github.com/maybevoid/ferrite" 8 | authors = [ "Soares Chen " ] 9 | license = "MIT OR Apache-2.0" 10 | keywords = [ "session-types" ] 11 | 12 | [dependencies] 13 | log = "0.4.14" 14 | rand = "0.7.3" 15 | futures = "0.3.15" 16 | env_logger = "0.8.3" 17 | ipc-channel = "0.14.1" 18 | ferrite-session = { path = "../ferrite-session" } 19 | tokio = { version = "1.15.0", features = [ "full" ] } 20 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/channel.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::VecDeque, 3 | future::Future, 4 | time::Duration, 5 | }; 6 | 7 | use ferrite_session::prelude::*; 8 | use tokio::time::sleep; 9 | 10 | // Example implementation of Rust channels using shared channels 11 | 12 | define_choice! { 13 | ReceiverOption < T > ; 14 | Next: SendValue < T, Z >, 15 | Close: End, 16 | } 17 | 18 | define_choice! { 19 | ChannelOption < T > ; 20 | ReceiveNext: ReceiveValue < T, Release >, 21 | SendNext: SendValue < 22 | Option < T >, 23 | Release 24 | >, 25 | } 26 | 27 | pub type Receiver = Rec>>; 28 | 29 | pub type Channel = LinearToShared>>; 30 | 31 | pub fn make_receiver( 32 | source: SharedChannel> 33 | ) -> Session> 34 | where 35 | T: Send + 'static, 36 | { 37 | acquire_shared_session(source.clone(), move |chan| { 38 | choose!( 39 | chan, 40 | SendNext, 41 | receive_value_from(chan, move |m_val| { 42 | match m_val { 43 | Some(val) => fix_session(offer_choice! { 44 | Next => { 45 | send_value ( 46 | val, 47 | release_shared_session ( chan, 48 | partial_session ( 49 | make_receiver ( source ) 50 | ) 51 | )) 52 | } 53 | Close => { 54 | release_shared_session ( chan, 55 | terminate () ) 56 | } 57 | }), 58 | None => step(async move { 59 | sleep(Duration::from_millis(100)).await; 60 | 61 | release_shared_session(chan, partial_session(make_receiver(source))) 62 | }), 63 | } 64 | }) 65 | ) 66 | }) 67 | } 68 | 69 | pub fn sender_session( 70 | source: SharedChannel>, 71 | make_val: impl FnOnce() -> Fut + Send + 'static, 72 | ) -> Session 73 | where 74 | T: Send + 'static, 75 | Fut: Future + Send, 76 | { 77 | acquire_shared_session(source, |chan| { 78 | choose!( 79 | chan, 80 | ReceiveNext, 81 | step(async move { 82 | send_value_to( 83 | chan, 84 | make_val().await, 85 | release_shared_session(chan, terminate()), 86 | ) 87 | }) 88 | ) 89 | }) 90 | } 91 | 92 | fn do_create_channel(mut queue: VecDeque) -> SharedSession> 93 | where 94 | T: Send + 'static, 95 | { 96 | accept_shared_session(async move { 97 | offer_choice! { 98 | ReceiveNext => { 99 | receive_value( |val| { 100 | queue.push_back ( val ); 101 | 102 | detach_shared_session ( 103 | do_create_channel ( queue ) ) 104 | }) 105 | } 106 | SendNext => { 107 | let m_val = queue.pop_front(); 108 | 109 | send_value ( m_val, 110 | detach_shared_session ( 111 | do_create_channel ( queue ) ) ) 112 | } 113 | } 114 | }) 115 | } 116 | 117 | pub fn create_channel() -> SharedChannel> 118 | where 119 | T: Send + 'static, 120 | { 121 | run_shared_session(do_create_channel(VecDeque::new())) 122 | } 123 | 124 | pub fn channel_session() -> Session 125 | { 126 | let channel: SharedChannel> = create_channel(); 127 | 128 | let consumer1: Session = 129 | include_session(make_receiver(channel.clone()), |receiver| { 130 | unfix_session( 131 | receiver, 132 | choose!( 133 | receiver, 134 | Next, 135 | receive_value_from(receiver, move |val| { 136 | println!("[Consumer 1] Receive first value: {}", val); 137 | 138 | unfix_session( 139 | receiver, 140 | choose!( 141 | receiver, 142 | Next, 143 | receive_value_from(receiver, move |val| { 144 | println!("[Consumer 1] Receive second value: {}", val); 145 | 146 | unfix_session( 147 | receiver, 148 | choose!(receiver, Close, wait(receiver, terminate())), 149 | ) 150 | }) 151 | ), 152 | ) 153 | }) 154 | ), 155 | ) 156 | }); 157 | 158 | let producer1: Session = 159 | sender_session(channel.clone(), move || async move { 160 | sleep(Duration::from_secs(2)).await; 161 | 162 | "hello".to_string() 163 | }); 164 | 165 | let producer2: Session = sender_session(channel.clone(), || { 166 | Box::pin(async { 167 | sleep(Duration::from_secs(1)).await; 168 | 169 | "world".to_string() 170 | }) 171 | }); 172 | 173 | let producer3: Session = sender_session(channel, || { 174 | Box::pin(async { 175 | sleep(Duration::from_secs(3)).await; 176 | 177 | "bye".to_string() 178 | }) 179 | }); 180 | 181 | wait_sessions( 182 | vec![consumer1, producer1, producer3, producer2], 183 | terminate(), 184 | ) 185 | } 186 | 187 | #[tokio::main] 188 | pub async fn main() 189 | { 190 | run_session(channel_session()).await; 191 | } 192 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/concat.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | time::Duration, 3 | vec::*, 4 | }; 5 | 6 | use ferrite_session::prelude::*; 7 | use tokio::time::sleep; 8 | 9 | pub fn concat_session() -> Session 10 | { 11 | let p1: Session< 12 | ReceiveValue< 13 | Vec, 14 | ReceiveValue, SendValue>, 15 | >, 16 | > = receive_value(|l1: Vec| { 17 | println!("[P1] Received first list: [{}]", l1.join(", ")); 18 | 19 | receive_value(|l2: Vec| { 20 | println!("[P1] Received second list: [{}]", l2.join(", ")); 21 | 22 | step(async move { 23 | send_value( 24 | { 25 | println!("[P1] Spending 3 seconds to concat lists"); 26 | sleep(Duration::from_secs(3)).await; 27 | 28 | let l5 = { 29 | let mut l3 = l1; 30 | let mut l4 = l2; 31 | l3.append(&mut l4); 32 | l3 33 | }; 34 | 35 | l5.join(", ") 36 | }, 37 | terminate_async(|| async { 38 | println!("[P1] Spending 2 seconds to cleanup"); 39 | sleep(Duration::from_secs(2)).await; 40 | println!("[P1] Terminating"); 41 | }), 42 | ) 43 | }) 44 | }) 45 | }); 46 | 47 | let p2: Session< 48 | ReceiveChannel< 49 | ReceiveValue< 50 | Vec, 51 | ReceiveValue, SendValue>, 52 | >, 53 | End, 54 | >, 55 | > = receive_channel(|val_chan| { 56 | step(async move { 57 | send_value_to( 58 | val_chan, 59 | { 60 | println!("[P2] spending 2 seconds to produce ['hello', 'world']"); 61 | sleep(Duration::from_secs(2)).await; 62 | 63 | vec!["hello".to_string(), "world".to_string()] 64 | }, 65 | step(async move { 66 | send_value_to( 67 | val_chan, 68 | { 69 | println!( 70 | "[P2] spending 1 second to produce ['foo', 'bar', 'baz']" 71 | ); 72 | sleep(Duration::from_secs(1)).await; 73 | 74 | vec!["foo".to_string(), "bar".to_string(), "baz".to_string()] 75 | }, 76 | receive_value_from(val_chan, move |res| { 77 | println!("[P2] received result from P1: [{}]", res); 78 | 79 | wait(val_chan, { 80 | println!("[P2] P1 has terminated"); 81 | 82 | terminate_async(|| async { 83 | println!("[P2] Spending 1 second to cleanup"); 84 | sleep(Duration::from_secs(1)).await; 85 | println!("[P2] Terminating"); 86 | }) 87 | }) 88 | }), 89 | ) 90 | }), 91 | ) 92 | }) 93 | }); 94 | 95 | apply_channel(p2, p1) 96 | } 97 | 98 | #[tokio::main] 99 | pub async fn main() 100 | { 101 | run_session(concat_session()).await; 102 | } 103 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/custom_choice.rs: -------------------------------------------------------------------------------- 1 | use ferrite_session::prelude::*; 2 | 3 | define_choice! { FooBarBaz; 4 | Foo : SendValue < String, End >, 5 | Bar : ReceiveValue < u64, End >, 6 | Baz : End, 7 | Quux : SendValue < i32, End >, 8 | } 9 | 10 | pub fn external_choice_session() -> Session 11 | { 12 | let provider: Session> = offer_choice! { 13 | Foo => { 14 | send_value( 15 | "provider_foo".to_string(), 16 | terminate() ) 17 | } 18 | Bar => { 19 | receive_value( |val| { 20 | println! ( "received bar value: {}", val ); 21 | terminate() 22 | }) 23 | } 24 | Baz => { 25 | terminate() 26 | } 27 | Quux => { 28 | send_value( 29 | 8, 30 | terminate() ) 31 | } 32 | }; 33 | 34 | let client_bar: Session, End>> = 35 | receive_channel(|chan| { 36 | choose!(chan, Bar, send_value_to(chan, 42, wait(chan, terminate()))) 37 | }); 38 | 39 | apply_channel(client_bar, provider) 40 | } 41 | 42 | #[tokio::main] 43 | pub async fn main() 44 | { 45 | run_session(external_choice_session()).await 46 | } 47 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/cut.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | pub use ferrite_session::prelude::*; 4 | use tokio::time::sleep; 5 | 6 | type Producer = SendValue; 7 | 8 | fn cut_session() -> Session 9 | { 10 | let client: Session< 11 | ReceiveChannel< 12 | Producer, 13 | ReceiveChannel>, 14 | >, 15 | > = receive_channels! ( (c1, c2, c3) => { 16 | cut! { 17 | [ R, L, R ] ; 18 | receive_value_from ( c2, move |x2| { 19 | step(async move { 20 | println! ("[right] got x2: {}", x2); 21 | sleep(Duration::from_secs(1)).await; 22 | 23 | wait( c2, 24 | terminate_async(|| async { 25 | println! ("[right] terminating"); 26 | }) ) 27 | }) 28 | }); 29 | c4 => { 30 | receive_value_from( c1, move |x1| { 31 | println! ("[left] got x1: {}", x1); 32 | 33 | receive_value_from ( c3, move |x3| { 34 | println! ("[left] got x3: {}", x3); 35 | 36 | wait_all! ( [ c1, c3, c4 ], 37 | terminate_async (|| async { 38 | println! ("[left] terminating"); 39 | }) ) 40 | }) 41 | }) 42 | } 43 | } 44 | }); 45 | 46 | let p1: Session = send_value("foo".to_string(), terminate()); 47 | 48 | let p2: Session = send_value("bar".to_string(), terminate()); 49 | 50 | let p3: Session = send_value("baz".to_string(), terminate()); 51 | 52 | apply_channel(apply_channel(apply_channel(client, p1), p2), p3) 53 | } 54 | 55 | #[tokio::main] 56 | pub async fn main() 57 | { 58 | run_session(cut_session()).await; 59 | } 60 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/detach.rs: -------------------------------------------------------------------------------- 1 | use ferrite_session::{ 2 | internal::protocol::Lock, 3 | prelude::*, 4 | }; 5 | 6 | type Counter = LinearToShared>; 7 | type Detached = ReceiveValue>; 8 | type CounterLock = Lock>; 9 | 10 | fn shared_provider_1(count: u64) -> SharedSession 11 | { 12 | accept_shared_session(async move { 13 | send_value(count, detach_shared_session(shared_provider_1(count + 1))) 14 | }) 15 | } 16 | 17 | fn detached_provider_1(counter: SharedChannel) -> Session 18 | { 19 | receive_value(move |count| { 20 | println!("[detached_provider_1] received count 1: {}", count); 21 | 22 | acquire_shared_session(counter, move |c| { 23 | receive_value_from(c, move |count| { 24 | println!("[detached_provider_1] received count 2: {}", count); 25 | forward(c) 26 | }) 27 | }) 28 | }) 29 | } 30 | 31 | fn detached_provider_2() -> Session> 32 | { 33 | receive_channel(move |_lock| { 34 | receive_value(move |count| { 35 | println!("[detached_provider_2] received count: {}", count); 36 | 37 | detach_shared_session(shared_provider_1(count + 1)) 38 | }) 39 | }) 40 | } 41 | 42 | fn shared_provider_2(count: u64) -> SharedSession 43 | { 44 | accept_shared_session(async move { 45 | send_value( 46 | count, 47 | include_session(detached_provider_2(), move |c| { 48 | send_channel_to(c, Z, send_value_to(c, count + 1, forward(c))) 49 | }), 50 | ) 51 | }) 52 | } 53 | 54 | fn detached_client() -> Session> 55 | { 56 | receive_channel(move |c| { 57 | send_value_to(c, 42, release_shared_session(c, terminate())) 58 | }) 59 | } 60 | 61 | fn shared_client() -> Session, End>> 62 | { 63 | receive_value(move |counter| { 64 | include_session(detached_provider_1(counter), move |c1| { 65 | include_session(detached_client(), move |c2| { 66 | send_channel_to(c2, c1, wait(c2, terminate())) 67 | }) 68 | }) 69 | }) 70 | } 71 | 72 | async fn run_shared_client(counter: SharedChannel) 73 | { 74 | run_session(include_session(shared_client(), move |c| { 75 | send_value_to(c, counter, wait(c, terminate())) 76 | })) 77 | .await; 78 | } 79 | 80 | #[tokio::main] 81 | pub async fn main() 82 | { 83 | let counter1 = run_shared_session(shared_provider_1(100)); 84 | let counter2 = run_shared_session(shared_provider_2(200)); 85 | 86 | run_shared_client(counter1).await; 87 | run_shared_client(counter2).await; 88 | } 89 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/dining_philosophers.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Exercise: Dining Philosophers 3 | 4 | In this exercise we will implement the dining philosophers 5 | problem using session type. 6 | 7 | - Implement the fork as shared process. 8 | 9 | - Each fork is identified by a unique ID represented as u8. 10 | 11 | - When the fork is acquired, prints 12 | "fork {id} has been acquired" 13 | 14 | - Implement the philosopher as a linear process. 15 | 16 | - Each philosopher is identified by a unique ID represented as u8 17 | 18 | - Each philosopher is given two shared channels, representing the 19 | left and right forks. 20 | 21 | - The philosopher starts thinking by printing 22 | "philosopher {id} is thinking", 23 | then pauses for 1 second. 24 | 25 | - After finished thinking, print 26 | "philosopher {id} is going to eat" 27 | 28 | - Try to acquire the left fork, then prints 29 | "philosopher {id} has acquired the left fork" 30 | 31 | - Try to acquire the right fork, then prints 32 | "philosopher {id} has acquired the right fork" 33 | 34 | - Print "philosopher {id} is eating", then pause for 1 second. 35 | 36 | - After finished eating, print 37 | "philosopher {} has finished eating and is releasing the forks", 38 | 39 | - Release the right fork, followed by the left fork. 40 | 41 | - Start from the beginning again. 42 | */ 43 | 44 | use std::time::Duration; 45 | 46 | use ferrite_session::prelude::*; 47 | use tokio::time::sleep; 48 | 49 | type Fork = LinearToShared; 50 | 51 | fn fork(id: u8) -> SharedSession 52 | { 53 | accept_shared_session(async move { 54 | step(async move { 55 | println!("fork {} has been acquired", id); 56 | detach_shared_session(fork(id)) 57 | }) 58 | }) 59 | } 60 | 61 | fn run_fork(id: u8) -> SharedChannel 62 | { 63 | run_shared_session(fork(id)) 64 | } 65 | 66 | fn philosopher( 67 | id: u8, 68 | left: SharedChannel, 69 | right: SharedChannel, 70 | ) -> Session 71 | { 72 | step(async move { 73 | println!("philosopher {} is thinking", id); 74 | sleep(Duration::from_secs(1)).await; 75 | 76 | println!("philosopher {} is going to eat", id); 77 | acquire_shared_session(left.clone(), move |left_fork| { 78 | println!("philosopher {} has acquired the left fork", id); 79 | acquire_shared_session(right.clone(), move |right_fork| { 80 | println!("philosopher {} has acquired the right fork", id); 81 | step(async move { 82 | println!("philosopher {} is eating", id); 83 | sleep(Duration::from_secs(1)).await; 84 | 85 | println!( 86 | "philosopher {} has finished eating and is releasing the forks", 87 | id 88 | ); 89 | 90 | release_shared_session( 91 | right_fork, 92 | release_shared_session( 93 | left_fork, 94 | include_session(philosopher(id, left, right), forward), 95 | ), 96 | ) 97 | }) 98 | }) 99 | }) 100 | }) 101 | } 102 | 103 | fn main_session() -> Session 104 | { 105 | let f0 = run_fork(0); 106 | let f1 = run_fork(1); 107 | let f2 = run_fork(2); 108 | let f3 = run_fork(3); 109 | 110 | let p0 = philosopher(0, f0, f1.clone()); 111 | let p1 = philosopher(1, f1.clone(), f2.clone()); 112 | let p2 = philosopher(2, f2, f3.clone()); 113 | 114 | // Using this version of p3 will result in deadlock: 115 | // let p3 = philosopher(3, f3, f1); 116 | 117 | let p3 = philosopher(3, f1, f3); 118 | 119 | include_session(p0, move |c0| { 120 | include_session(p1, move |c1| { 121 | include_session(p2, move |c2| { 122 | include_session(p3, move |c3| wait_all!([c0, c1, c2, c3], terminate())) 123 | }) 124 | }) 125 | }) 126 | } 127 | 128 | #[tokio::main] 129 | pub async fn main() 130 | { 131 | env_logger::init(); 132 | 133 | run_session(main_session()).await; 134 | } 135 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/external_choice.rs: -------------------------------------------------------------------------------- 1 | use ferrite_session::{ 2 | either::*, 3 | prelude::*, 4 | }; 5 | 6 | pub fn external_choice_session() -> Session 7 | { 8 | let provider: Session< 9 | ExternalChoice, ReceiveValue>>, 10 | > = offer_choice! { 11 | Left => { 12 | send_value( 13 | "provider_left".to_string(), 14 | terminate() ) 15 | } 16 | Right => { 17 | receive_value( |val| { 18 | println! ( "received value: {}", val ); 19 | terminate() 20 | }) 21 | } 22 | }; 23 | 24 | let _client_left: Session< 25 | ReceiveChannel< 26 | ExternalChoice, ReceiveValue>>, 27 | End, 28 | >, 29 | > = receive_channel(|chan| { 30 | choose!( 31 | chan, 32 | Left, 33 | receive_value_from(chan, move |val: String| { 34 | println!("received string: {}", val); 35 | 36 | wait(chan, terminate()) 37 | }) 38 | ) 39 | }); 40 | 41 | let client_right: Session< 42 | ReceiveChannel< 43 | ExternalChoice, ReceiveValue>>, 44 | End, 45 | >, 46 | > = receive_channel(|chan| { 47 | choose!( 48 | chan, 49 | Right, 50 | send_value_to(chan, 42, wait(chan, terminate())) 51 | ) 52 | }); 53 | 54 | apply_channel(client_right, provider) 55 | } 56 | 57 | #[tokio::main] 58 | pub async fn main() 59 | { 60 | run_session(external_choice_session()).await 61 | } 62 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/hello.rs: -------------------------------------------------------------------------------- 1 | use std::format; 2 | 3 | use ferrite_session::prelude::*; 4 | 5 | type HelloSession = ReceiveValue>; 6 | 7 | pub fn hello_session() -> Session 8 | { 9 | let server: Session = 10 | receive_value(|name| send_value(format!("Hello, {}!", name), terminate())); 11 | 12 | let client: Session> = 13 | receive_channel(|x| { 14 | send_value_to( 15 | x, 16 | "John".to_string(), 17 | receive_value_from(x, move |result| { 18 | println!("{}", result); 19 | wait(x, terminate()) 20 | }), 21 | ) 22 | }); 23 | 24 | apply_channel(client, server) 25 | } 26 | 27 | #[tokio::main] 28 | pub async fn main() 29 | { 30 | run_session(hello_session()).await 31 | } 32 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/internal_choice.rs: -------------------------------------------------------------------------------- 1 | use ferrite_session::{ 2 | either::*, 3 | prelude::*, 4 | }; 5 | 6 | pub fn internal_choice_session() -> Session 7 | { 8 | let client: Session< 9 | ReceiveChannel< 10 | InternalChoice, ReceiveValue>>, 11 | End, 12 | >, 13 | > = receive_channel(|chan| { 14 | case! { chan ; 15 | Left => { 16 | receive_value_from ( chan, 17 | move |val: String| { 18 | println! ("received string: {}", val); 19 | wait ( chan, 20 | terminate () ) 21 | }) 22 | } 23 | Right => { 24 | send_value_to ( chan, 25 | 42, 26 | wait ( chan, 27 | terminate () ) ) 28 | } 29 | } 30 | }); 31 | 32 | let provider_left: Session< 33 | InternalChoice, ReceiveValue>>, 34 | > = offer_case!(Left, send_value("provider_left".to_string(), terminate())); 35 | 36 | let _provider_right: Session< 37 | InternalChoice, ReceiveValue>>, 38 | > = offer_case!( 39 | Right, 40 | receive_value(|val: u64| { 41 | println!("received int: {}", val); 42 | terminate() 43 | }) 44 | ); 45 | 46 | apply_channel(client, provider_left) 47 | } 48 | 49 | #[tokio::main] 50 | pub async fn main() 51 | { 52 | run_session(internal_choice_session()).await 53 | } 54 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/message.rs: -------------------------------------------------------------------------------- 1 | use ferrite_session::prelude::*; 2 | use futures::future::join_all; 3 | use ipc_channel::ipc; 4 | 5 | define_choice! { CounterCommand; 6 | Increment: Release, 7 | GetCount: SendValue < u64, Release >, 8 | } 9 | 10 | type CounterSession = LinearToShared>; 11 | 12 | fn make_counter_session(count: u64) -> SharedSession 13 | { 14 | accept_shared_session(async move { 15 | offer_choice! { 16 | Increment => { 17 | println!("provider incrementing count {}", count); 18 | 19 | detach_shared_session ( 20 | make_counter_session ( count + 1 ) 21 | ) 22 | } 23 | GetCount => { 24 | println!("provider sending back count {}", count); 25 | send_value ( count, 26 | detach_shared_session ( 27 | make_counter_session ( count ) ) ) 28 | } 29 | } 30 | }) 31 | } 32 | 33 | async fn use_counter( 34 | counter: SharedChannel, 35 | count: u64, 36 | ) -> u64 37 | { 38 | let mut futures = vec![]; 39 | 40 | for i in 0..count { 41 | let future = async_acquire_shared_session(counter.clone(), move |chan| { 42 | choose!( 43 | chan, 44 | Increment, 45 | step(async move { 46 | println!("client incremented counter"); 47 | release_shared_session(chan, terminate()) 48 | }) 49 | ) 50 | }); 51 | 52 | futures.push(future); 53 | 54 | if i % 1000 == 0 { 55 | join_all(futures.drain(0..)).await; 56 | } 57 | } 58 | 59 | join_all(futures).await; 60 | 61 | run_session_with_result(acquire_shared_session(counter, |chan| { 62 | choose!( 63 | chan, 64 | GetCount, 65 | receive_value_from(chan, move |count| release_shared_session( 66 | chan, 67 | send_value(count, terminate()) 68 | )) 69 | ) 70 | })) 71 | .await 72 | } 73 | 74 | #[tokio::main] 75 | 76 | pub async fn main() 77 | { 78 | env_logger::init(); 79 | 80 | let counter = run_shared_session(make_counter_session(0)); 81 | 82 | let (sender, receiver) = ipc::channel().unwrap(); 83 | 84 | sender.send(counter).unwrap(); 85 | 86 | let shared = receiver.recv().unwrap(); 87 | 88 | // let shared = counter.clone(); 89 | 90 | let count = use_counter(shared, 10000).await; 91 | 92 | println!("count: {}", count); 93 | } 94 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/nested_recursive.rs: -------------------------------------------------------------------------------- 1 | use ferrite_session::{ 2 | either::*, 3 | prelude::*, 4 | }; 5 | 6 | type Stream = Rec< 7 | ExternalChoice< 8 | Either< 9 | Rec, S>>>, 10 | ReceiveValue, 11 | >, 12 | >, 13 | >; 14 | 15 | fn producer() -> Session 16 | { 17 | fix_session(offer_choice! { 18 | Left => 19 | fix_session(offer_case!( 20 | Left, 21 | send_value( 22 | "foo".to_string(), 23 | fix_session(offer_case!( 24 | Left, 25 | send_value( 26 | "bar".to_string(), 27 | fix_session(offer_case!(Right, producer())) 28 | ) 29 | )) 30 | ))) 31 | Right => 32 | receive_value(| str | { 33 | println!("[producer] received string: {}", str); 34 | terminate() 35 | }) 36 | }) 37 | } 38 | 39 | fn consume_input() -> Session< 40 | ReceiveChannel< 41 | RecX, S>>>, 42 | End, 43 | >, 44 | > 45 | { 46 | receive_channel(|chan| { 47 | unfix_session( 48 | chan, 49 | case! { chan; 50 | Left => 51 | receive_value_from(chan, move | val | { 52 | println!("[consumer] received value: {}", val); 53 | include_session(consume_input(), | consume | 54 | send_channel_to(consume, chan, 55 | wait(consume, terminate()))) 56 | }), 57 | Right => 58 | unfix_session(chan, 59 | choose!(chan, Right, 60 | send_value_to(chan, 61 | "hello".to_string(), 62 | wait(chan, 63 | terminate())))) 64 | }, 65 | ) 66 | }) 67 | } 68 | 69 | fn consumer() -> Session> 70 | { 71 | include_session(consume_input(), |consume| { 72 | receive_channel(|chan| { 73 | unfix_session( 74 | chan, 75 | choose!( 76 | chan, 77 | Left, 78 | send_channel_to(consume, chan, wait(consume, terminate())) 79 | ), 80 | ) 81 | }) 82 | }) 83 | } 84 | 85 | #[tokio::main] 86 | pub async fn main() 87 | { 88 | run_session(apply_channel(consumer(), producer())).await 89 | } 90 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/pair.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use ferrite_session::prelude::*; 4 | use tokio::time::sleep; 5 | 6 | pub fn pair_session() -> Session 7 | { 8 | let p1: Session> = step(async { 9 | println!("[P1] Spending 7 seconds to produce first output"); 10 | sleep(Duration::from_secs(7)).await; 11 | println!("[P1] Done producing first output - 42"); 12 | 13 | send_value( 14 | 42, 15 | terminate_async(|| async { 16 | println!("[P1] Spending 3 seconds to cleanup"); 17 | sleep(Duration::from_secs(3)).await; 18 | println!("[P1] Terminating"); 19 | }), 20 | ) 21 | }); 22 | 23 | let p2: Session< 24 | ReceiveChannel< 25 | SendValue, 26 | SendChannel, SendValue>, 27 | >, 28 | > = receive_channel(|val_chan| { 29 | send_channel_from( 30 | val_chan, 31 | step(async move { 32 | println!("[P2] Spending 2 seconds to produce second output"); 33 | sleep(Duration::from_secs(2)).await; 34 | println!("[P2] Done producing second output - Hello World"); 35 | 36 | send_value( 37 | "Hello World".to_string(), 38 | terminate_async(|| async { 39 | println!("[P2] Spending 10 seconds to cleanup"); 40 | sleep(Duration::from_secs(10)).await; 41 | println!("[P2] Terminating"); 42 | }), 43 | ) 44 | }), 45 | ) 46 | }); 47 | 48 | let p3: Session< 49 | ReceiveChannel< 50 | SendChannel, SendValue>, 51 | ReceiveChannel, 52 | >, 53 | > = receive_channel(|str_chan| { 54 | receive_channel(|timer_chan| { 55 | wait( 56 | timer_chan, 57 | step(async move { 58 | println!("[P3] P4 has terminated. Receiving channel from P1"); 59 | 60 | receive_channel_from(str_chan, |int_chan| { 61 | receive_value_from(int_chan, move |input1| { 62 | println!("[P3] Received input from P1: {}", input1); 63 | 64 | wait( 65 | int_chan, 66 | step(async move { 67 | println!("[P3] P1 has terminated"); 68 | 69 | receive_value_from(str_chan, move |input2| { 70 | println!("[P3] Received input from P2: {}", input2); 71 | 72 | wait( 73 | str_chan, 74 | step(async move { 75 | println!("[P3] P2 has terminated"); 76 | 77 | terminate_async(|| async { 78 | println!("[P3] Spending 2 seconds to clean up"); 79 | sleep(Duration::from_secs(2)).await; 80 | println!("[P3] Terminating"); 81 | }) 82 | }), 83 | ) 84 | }) 85 | }), 86 | ) 87 | }) 88 | }) 89 | }), 90 | ) 91 | }) 92 | }); 93 | 94 | let p4: Session = terminate_async(|| async { 95 | println!("[P4] Sleeping for 3 seconds before terminating"); 96 | 97 | sleep(Duration::from_secs(2)).await; 98 | 99 | println!("[P4] Terminating"); 100 | }); 101 | 102 | let p5: Session, SendValue>> = 103 | apply_channel(p2, p1); 104 | 105 | let p6: Session = apply_channel(apply_channel(p3, p5), p4); 106 | 107 | p6 108 | } 109 | 110 | #[tokio::main] 111 | 112 | pub async fn main() 113 | { 114 | run_session(pair_session()).await 115 | } 116 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/queue.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | future::Future, 3 | time::Duration, 4 | }; 5 | 6 | use ferrite_session::{ 7 | either::*, 8 | prelude::*, 9 | }; 10 | use tokio::time::sleep; 11 | 12 | type Queue = Rec>>>; 13 | 14 | type StringQueue = Queue; 15 | 16 | fn nil_queue() -> Session> 17 | where 18 | A: Send + 'static, 19 | { 20 | fix_session(offer_case(LeftLabel, terminate())) 21 | } 22 | 23 | fn append_queue( 24 | builder: Func, 25 | rest: Session>, 26 | ) -> Session> 27 | where 28 | A: Send + 'static, 29 | Func: FnOnce() -> Fut + Send + 'static, 30 | Fut: Future + Send + 'static, 31 | { 32 | fix_session(offer_case!( 33 | Right, 34 | step(async move { send_value(builder().await, rest) }) 35 | )) 36 | } 37 | 38 | fn read_queue() -> Session> 39 | { 40 | receive_channel(|queue| { 41 | unfix_session( 42 | queue, 43 | case! { queue ; 44 | Left => { 45 | wait ( queue, terminate () ) 46 | } 47 | Right => { 48 | receive_value_from( queue, 49 | move |val| { 50 | println!("Receive value: {}", val); 51 | 52 | include_session ( 53 | read_queue (), 54 | |next| { 55 | send_channel_to ( 56 | next, 57 | queue, 58 | forward ( next ) 59 | ) }) 60 | } ) 61 | } 62 | }, 63 | ) 64 | }) 65 | } 66 | 67 | pub fn queue_session() -> Session 68 | { 69 | let p11: Session = nil_queue(); 70 | 71 | let p12: Session = append_queue( 72 | || async { 73 | println!("producing world.."); 74 | 75 | sleep(Duration::from_secs(3)).await; 76 | 77 | "World".to_string() 78 | }, 79 | p11, 80 | ); 81 | 82 | let p13: Session = append_queue( 83 | || async { 84 | println!("producing hello.."); 85 | 86 | sleep(Duration::from_secs(2)).await; 87 | 88 | "Hello".to_string() 89 | }, 90 | p12, 91 | ); 92 | 93 | apply_channel(read_queue(), p13) 94 | } 95 | 96 | #[tokio::main] 97 | 98 | pub async fn main() 99 | { 100 | run_session(queue_session()).await; 101 | } 102 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/restaurant.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use ferrite_session::prelude::*; 4 | use tokio::time::sleep; 5 | 6 | pub struct MushroomSoup {} 7 | 8 | pub struct TomatoSoup {} 9 | 10 | pub struct BeefSteak {} 11 | 12 | pub struct PorkChop {} 13 | 14 | define_choice! { 15 | SoupMenu ; 16 | MushroomMenu: SendValue < MushroomSoup, End >, 17 | TomatoMenu: SendValue < TomatoSoup, End >, 18 | } 19 | 20 | define_choice! { 21 | MainMenu ; 22 | BeefMenu: SendValue < BeefSteak, End >, 23 | PorkMenu: SendValue < PorkChop, End >, 24 | } 25 | 26 | pub fn restaurant_session() -> Session 27 | { 28 | let soup_of_the_day: Session> = offer_case( 29 | MushroomMenuLabel, 30 | step(async move { 31 | send_value( 32 | { 33 | println!("[Soup] Spending 3 seconds to prepare mushroom soup"); 34 | 35 | sleep(Duration::from_secs(2)).await; 36 | 37 | println!("[Soup] Finished preparing mushroom soup"); 38 | 39 | MushroomSoup {} 40 | }, 41 | terminate_async(|| async { 42 | println!("[Soup] Served mushroom soup. Terminating soup protocol"); 43 | }), 44 | ) 45 | }), 46 | ); 47 | 48 | let main_dish: Session> = offer_choice! { 49 | BeefMenu => { 50 | println!("[MainCourse] Customer chose to eat beef steak"); 51 | 52 | step(async move { 53 | println!("[MainCourse] Spending 7 seconds to prepare beef steak"); 54 | sleep(Duration::from_secs(7)).await; 55 | 56 | send_value(BeefSteak{}, 57 | terminate_async (|| async { 58 | println!("[MainCourse] Served beef steak. Terminating main course protocol"); 59 | })) 60 | }) 61 | } 62 | PorkMenu => { 63 | println!("[MainCourse] Customer chose to eat pork chop"); 64 | 65 | println!("[MainCourse] Spending 5 seconds to prepare pork chop"); 66 | sleep(Duration::from_secs(5)).await; 67 | 68 | send_value (PorkChop{}, 69 | terminate_async (|| async { 70 | println!("[MainCourse] Served pork chop. Terminating main course protocol"); 71 | }) ) 72 | } 73 | }; 74 | 75 | let menu: Session< 76 | SendChannel, ExternalChoice>, 77 | > = include_session(soup_of_the_day, |chan| { 78 | send_channel_from(chan, partial_session(main_dish)) 79 | }); 80 | 81 | let diner: Session< 82 | ReceiveChannel< 83 | SendChannel, ExternalChoice>, 84 | End, 85 | >, 86 | > = receive_channel(|menu_chan| { 87 | receive_channel_from(menu_chan, |soup_chan| { 88 | case! { soup_chan ; 89 | MushroomMenu => { 90 | println!("[Diner] Restaurant offers mushroom soup today"); 91 | 92 | receive_value_from ( soup_chan, move |_mushroom_soup| { 93 | println!("[Diner] Received mushroom soup. Spending 2 seconds drinking it"); 94 | 95 | step(async move { 96 | sleep(Duration::from_secs(2)).await; 97 | println!("[Diner] Finished drinking mushroom soup"); 98 | 99 | println!("[Diner] Choosing pork chop for main"); 100 | 101 | wait(soup_chan, 102 | step(async move { 103 | println!("[Diner] Soup protocol terminated"); 104 | 105 | choose! ( menu_chan, PorkMenu, 106 | receive_value_from ( menu_chan, move |_pork_chop| { 107 | println!("[Diner] Received pork chop. Spending 5 seconds eating it"); 108 | 109 | step(async move { 110 | sleep(Duration::from_secs(5)).await; 111 | println!("[Diner] Finished eating pork chop"); 112 | 113 | wait( menu_chan, 114 | step(async move { 115 | println!("[Diner] Main course protocol terminated"); 116 | 117 | terminate_async (|| async { 118 | println!("[Diner] Spending 4 seconds in washroom"); 119 | sleep(Duration::from_secs(4)).await; 120 | println!("[Diner] Leaving restaurant"); 121 | }) 122 | })) 123 | }) 124 | }) 125 | ) 126 | })) 127 | }) 128 | }) 129 | } 130 | TomatoMenu => { 131 | println!("[Diner] Restaurant offers tomato soup today"); 132 | 133 | receive_value_from( soup_chan, move |_tomato_soup| { 134 | println!("[Diner] Received tomato soup. Spending 1 second drinking it"); 135 | 136 | step(async move { 137 | sleep(Duration::from_secs(1)).await; 138 | 139 | println!("[Diner] finished drinking tomato soup"); 140 | println!("[Diner] Choosing beef steak for main"); 141 | 142 | wait ( soup_chan, { 143 | println!("[Diner] Soup protocol terminated"); 144 | 145 | choose! ( menu_chan, BeefMenu, 146 | receive_value_from( menu_chan, move |_beef_steak| { 147 | println!("[Diner] Received beef steak. Spending 6 seconds eating it"); 148 | 149 | step(async move { 150 | sleep(Duration::from_secs(6)).await; 151 | println!("[Diner] Finished eating beef steak."); 152 | 153 | wait ( menu_chan, 154 | step(async move { 155 | println!("[Diner] Main course protocol terminated"); 156 | 157 | terminate_async (|| async { 158 | println!("[Diner] Spending 3 seconds in washroom"); 159 | sleep(Duration::from_secs(3)).await; 160 | println!("[Diner] Leaving restaurant"); 161 | }) 162 | })) 163 | }) 164 | })) 165 | }) 166 | }) 167 | }) 168 | } 169 | } 170 | }) 171 | }); 172 | 173 | apply_channel(diner, menu) 174 | } 175 | 176 | #[tokio::main] 177 | 178 | pub async fn main() 179 | { 180 | run_session(restaurant_session()).await; 181 | } 182 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/shared.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use ferrite_session::prelude::*; 4 | use ipc_channel::ipc; 5 | use rand::prelude::*; 6 | use tokio::time::sleep; 7 | 8 | type SharedCounter = LinearToShared>; 9 | 10 | async fn random_sleep() 11 | { 12 | let sleep_time = thread_rng().gen_range(50, 100); 13 | sleep(Duration::from_millis(sleep_time)).await; 14 | } 15 | 16 | pub fn make_counter_session(count: u64) -> SharedSession 17 | { 18 | accept_shared_session(async move { 19 | println!("[Server] Producing count {}", count); 20 | random_sleep().await; 21 | println!("[Server] Produced count {}", count); 22 | 23 | send_value( 24 | count, 25 | detach_shared_session(make_counter_session(count + 1)), 26 | ) 27 | }) 28 | } 29 | 30 | pub fn read_counter_session( 31 | name: String, 32 | stop_at: u64, 33 | shared: SharedChannel, 34 | ) -> Session 35 | { 36 | let shared2 = shared.clone(); 37 | 38 | step(async move { 39 | random_sleep().await; 40 | 41 | acquire_shared_session(shared, move |counter| { 42 | receive_value_from(counter, move |count| { 43 | println!("[{}] Received count: {}", name, count); 44 | 45 | release_shared_session(counter, { 46 | if stop_at <= count { 47 | println!("[{}] terminating", name); 48 | terminate() 49 | } else { 50 | partial_session(read_counter_session(name, stop_at, shared2)) 51 | } 52 | }) 53 | }) 54 | }) 55 | }) 56 | } 57 | 58 | pub fn read_counter_session_2( 59 | shared_counter: &SharedChannel 60 | ) -> Session 61 | { 62 | acquire_shared_session(shared_counter.clone(), move |linear_counter| { 63 | step(async move { 64 | random_sleep().await; 65 | receive_value_from(linear_counter, move |count| { 66 | println!("Received count: {}", count); 67 | release_shared_session(linear_counter, terminate()) 68 | }) 69 | }) 70 | }) 71 | } 72 | 73 | pub fn shared_counter_session() -> Session 74 | { 75 | let shared = run_shared_session(make_counter_session(0)); 76 | 77 | // Sending a shared channel through IPC channel causes it 78 | // to be serialized and deserialized through OS socket. 79 | let (sender, receiver) = ipc::channel().unwrap(); 80 | sender.send(shared).unwrap(); 81 | let shared = receiver.recv().unwrap(); 82 | 83 | let mut sessions = vec![]; 84 | 85 | for i in 0..100 { 86 | sessions.push(read_counter_session(format!("P{}", i), 10, shared.clone())); 87 | } 88 | 89 | wait_sessions(sessions, terminate()) 90 | } 91 | 92 | #[tokio::main] 93 | pub async fn main() 94 | { 95 | env_logger::init(); 96 | 97 | run_session(shared_counter_session()).await; 98 | } 99 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/shared_queue.rs: -------------------------------------------------------------------------------- 1 | use ferrite_session::prelude::*; 2 | 3 | /* 4 | # Excercise: Shared Queue 5 | 6 | - Implement a shared queue provider with a `Vec` internal state 7 | and provides the following operations: 8 | 9 | - Enqueue: Receive a string value, enqueue it to the back of of the queue 10 | and then release. 11 | 12 | - Dequeue: 13 | - If the queue is not empty, pop the front of the queue and send the value 14 | as `Some(res)`. 15 | - If the queue is empty, sends `None`. 16 | 17 | - Implement an `enqueue` function, which takes a `SharedChannel` 18 | and a string value. The function would run a Ferrite session that 19 | acquires the shared proess, choose Enqueue, and sends the value to 20 | the shared queue process. 21 | 22 | - Implement a `dequeue` function, which takes a `SharedChannel` 23 | and does the following: 24 | 25 | - Run a Ferrite session that acquires the shared proess 26 | - Choose Dequeue and receives the value. 27 | - If the result is `Some(val)`, print "Gotten dequeue value: {val}" 28 | - If the result is `None`, print "Dequeue returns None". 29 | 30 | The provided main function will spawn a shared queue, and call 31 | the `enqueue` and `dequeue` functions with different parameters. 32 | 33 | You should get the following result running the program: 34 | 35 | ``` 36 | $ cargo run --bin shared_queue 37 | Gotten dequeue value: World 38 | Gotten dequeue value: Hello 39 | Dequeue returns None 40 | ``` 41 | */ 42 | 43 | type Queue = LinearToShared>; 44 | 45 | define_choice! { QueueOps; 46 | Enqueue: ReceiveValue, 47 | Dequeue: SendValue, Release> 48 | } 49 | 50 | fn shared_queue(mut queue: Vec) -> SharedSession 51 | { 52 | accept_shared_session(async move { 53 | offer_choice! { 54 | Enqueue => { 55 | receive_value(move |val: String| { 56 | queue.push(val); 57 | detach_shared_session(shared_queue(queue)) 58 | }) 59 | } 60 | Dequeue => { 61 | send_value(queue.pop(), 62 | detach_shared_session(shared_queue(queue))) 63 | } 64 | } 65 | }) 66 | } 67 | 68 | fn create_shared_queue() -> SharedChannel 69 | { 70 | run_shared_session(shared_queue(vec![])) 71 | } 72 | 73 | async fn enqueue( 74 | queue: SharedChannel, 75 | val: String, 76 | ) 77 | { 78 | run_session(acquire_shared_session(queue, move |chan| { 79 | choose!( 80 | chan, 81 | Enqueue, 82 | send_value_to(chan, val, release_shared_session(chan, terminate())) 83 | ) 84 | })) 85 | .await; 86 | } 87 | 88 | async fn dequeue_and_print(queue: SharedChannel) 89 | { 90 | // todo!("Implement dequeue client here"); 91 | run_session(acquire_shared_session(queue, move |chan| { 92 | choose!( 93 | chan, 94 | Dequeue, 95 | receive_value_from(chan, move |val| { 96 | match val { 97 | Some(val) => { 98 | println!("Gotten dequeue value: {}", val); 99 | } 100 | None => { 101 | println!("Dequeue returns None"); 102 | } 103 | } 104 | 105 | release_shared_session(chan, terminate()) 106 | }) 107 | ) 108 | })) 109 | .await 110 | } 111 | 112 | #[tokio::main] 113 | pub async fn main() 114 | { 115 | env_logger::init(); 116 | 117 | let queue = create_shared_queue(); 118 | 119 | enqueue(queue.clone(), "Hello".to_string()).await; 120 | enqueue(queue.clone(), "World".to_string()).await; 121 | 122 | dequeue_and_print(queue.clone()).await; 123 | dequeue_and_print(queue.clone()).await; 124 | dequeue_and_print(queue.clone()).await; 125 | } 126 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/stream.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use ferrite_session::prelude::*; 4 | use tokio::time::sleep; 5 | 6 | type IntStream = Rec>; 7 | 8 | fn producer(count: u64) -> Session 9 | { 10 | fix_session(step(async move { 11 | println!("[producer] Producing value: {}", count); 12 | sleep(Duration::from_secs(1)).await; 13 | send_value(count, producer(count + 1)) 14 | })) 15 | } 16 | 17 | fn consumer() -> Session> 18 | { 19 | receive_channel(move |stream| { 20 | unfix_session( 21 | stream, 22 | receive_value_from(stream, move |count| { 23 | println!("[consumer] Received value: {}", count); 24 | include_session(consumer(), |next| { 25 | send_channel_to(next, stream, forward(next)) 26 | }) 27 | }), 28 | ) 29 | }) 30 | } 31 | 32 | pub fn stream_session() -> Session 33 | { 34 | let p1 = producer(0); 35 | 36 | let p2 = consumer(); 37 | 38 | apply_channel(p2, p1) 39 | } 40 | 41 | #[tokio::main] 42 | 43 | pub async fn main() 44 | { 45 | run_session(stream_session()).await; 46 | } 47 | -------------------------------------------------------------------------------- /ferrite-demo/src/bin/wrap_stream.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use ferrite_session::prelude::*; 4 | use tokio::time::sleep; 5 | 6 | struct WrapIntStream; 7 | 8 | impl Wrapper for WrapIntStream 9 | { 10 | type Unwrap = IntStream; 11 | } 12 | 13 | type IntStream = SendValue>; 14 | 15 | fn producer(count: u64) -> Session 16 | { 17 | step(async move { 18 | println!("Producing value: {}", count); 19 | sleep(Duration::from_secs(1)).await; 20 | 21 | send_value(count, wrap_session(producer(count + 1))) 22 | }) 23 | } 24 | 25 | fn consumer() -> Session> 26 | { 27 | receive_channel(|stream| { 28 | receive_value_from(stream, move |count| { 29 | println!("Received value: {}", count); 30 | unwrap_session( 31 | stream, 32 | include_session(consumer(), |next| { 33 | send_channel_to(next, stream, forward(next)) 34 | }), 35 | ) 36 | }) 37 | }) 38 | } 39 | 40 | pub fn stream_session() -> Session 41 | { 42 | let p1 = producer(0); 43 | 44 | let p2 = consumer(); 45 | 46 | apply_channel(p2, p1) 47 | } 48 | 49 | #[tokio::main] 50 | 51 | pub async fn main() 52 | { 53 | run_session(stream_session()).await 54 | } 55 | -------------------------------------------------------------------------------- /ferrite-session/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ferrite-session" 3 | version = "0.3.0" 4 | edition = "2018" 5 | description = "Session Types DSL for Rust" 6 | homepage = "https://github.com/maybevoid/ferrite" 7 | repository = "https://github.com/maybevoid/ferrite" 8 | authors = [ "Soares Chen " ] 9 | license = "MIT OR Apache-2.0" 10 | keywords = [ "session-types" ] 11 | readme = "../README.md" 12 | 13 | [dependencies] 14 | log = "0.4.17" 15 | paste = "1.0.7" 16 | ipc-channel = "0.16.0" 17 | tokio = { version = "1.19.1", features = [ "full" ] } 18 | serde = { version = "1.0.137", features = [ "derive" ] } 19 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/channel/functions.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | use std::sync::{ 3 | Arc, 4 | Mutex, 5 | }; 6 | 7 | use ipc_channel::ipc; 8 | use tokio::sync::{ 9 | mpsc, 10 | oneshot, 11 | Mutex as AsyncMutex, 12 | }; 13 | 14 | use super::types::*; 15 | 16 | pub fn once_channel() -> (SenderOnce, ReceiverOnce) 17 | { 18 | let (sender, receiver) = oneshot::channel(); 19 | 20 | (SenderOnce(sender), ReceiverOnce(receiver)) 21 | } 22 | 23 | pub fn unbounded() -> (Sender, Receiver) 24 | { 25 | let (sender, receiver) = mpsc::unbounded_channel(); 26 | 27 | ( 28 | Sender(sender), 29 | Receiver(Arc::new(AsyncMutex::new(receiver))), 30 | ) 31 | } 32 | 33 | pub fn ipc_channel() -> (IpcSender, IpcReceiver) 34 | where 35 | IpcReceiver: Send, 36 | { 37 | let (sender, receiver) = opaque_channel(); 38 | 39 | ( 40 | IpcSender { 41 | sender, 42 | phantom: PhantomData, 43 | }, 44 | IpcReceiver { 45 | receiver, 46 | phantom: PhantomData, 47 | }, 48 | ) 49 | } 50 | 51 | pub fn opaque_channel() -> (OpaqueSender, OpaqueReceiver) 52 | { 53 | let (sender, receiver) = ipc::channel::<()>().unwrap(); 54 | 55 | ( 56 | OpaqueSender(Arc::new(Mutex::new(Some(sender.to_opaque())))), 57 | OpaqueReceiver(Arc::new(Mutex::new(Some(receiver.to_opaque())))), 58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/channel/impls.rs: -------------------------------------------------------------------------------- 1 | use serde::{ 2 | self, 3 | Deserialize, 4 | Serialize, 5 | }; 6 | use tokio::task; 7 | 8 | use super::{ 9 | functions::*, 10 | traits::ForwardChannel, 11 | types::*, 12 | }; 13 | use crate::internal::functional::*; 14 | 15 | impl Clone for Sender 16 | { 17 | fn clone(&self) -> Sender 18 | { 19 | Sender(self.0.clone()) 20 | } 21 | } 22 | 23 | impl Clone for Receiver 24 | { 25 | fn clone(&self) -> Receiver 26 | { 27 | Receiver(self.0.clone()) 28 | } 29 | } 30 | 31 | impl Sender 32 | { 33 | pub fn send( 34 | &self, 35 | msg: T, 36 | ) -> Result<(), SendError> 37 | { 38 | self 39 | .0 40 | .send(msg) 41 | .map_err(|_| SendError(String::from("failed to send"))) 42 | } 43 | } 44 | 45 | impl ForwardChannel for () 46 | { 47 | fn forward_to( 48 | self, 49 | _: OpaqueSender, 50 | _: OpaqueReceiver, 51 | ) 52 | { 53 | } 54 | 55 | fn forward_from( 56 | _: OpaqueSender, 57 | _: OpaqueReceiver, 58 | ) -> Self 59 | { 60 | } 61 | } 62 | 63 | impl ForwardChannel for SenderOnce 64 | where 65 | T: ForwardChannel, 66 | { 67 | fn forward_to( 68 | self, 69 | sender: OpaqueSender, 70 | receiver: OpaqueReceiver, 71 | ) 72 | { 73 | task::spawn_blocking(move || { 74 | receiver.recv::<()>().unwrap(); 75 | 76 | let payload = T::forward_from(sender, receiver); 77 | 78 | self.send(payload).unwrap(); 79 | }); 80 | } 81 | 82 | fn forward_from( 83 | sender1: OpaqueSender, 84 | receiver1: OpaqueReceiver, 85 | ) -> Self 86 | { 87 | let (sender2, receiver2) = once_channel(); 88 | 89 | task::spawn(async move { 90 | let payload: T = receiver2.recv().await.unwrap(); 91 | 92 | task::spawn_blocking(move || { 93 | sender1.send(()); 94 | 95 | payload.forward_to(sender1, receiver1); 96 | }); 97 | }); 98 | 99 | sender2 100 | } 101 | } 102 | 103 | impl ForwardChannel for ReceiverOnce 104 | where 105 | T: ForwardChannel, 106 | { 107 | fn forward_to( 108 | self, 109 | sender1: OpaqueSender, 110 | receiver1: OpaqueReceiver, 111 | ) 112 | { 113 | task::spawn(async move { 114 | let channel = self.recv().await.unwrap(); 115 | 116 | task::spawn_blocking(move || { 117 | sender1.send(()); 118 | 119 | channel.forward_to(sender1, receiver1); 120 | }); 121 | }); 122 | } 123 | 124 | fn forward_from( 125 | sender1: OpaqueSender, 126 | receiver1: OpaqueReceiver, 127 | ) -> Self 128 | { 129 | let (sender2, receiver2) = once_channel(); 130 | 131 | task::spawn_blocking(move || { 132 | receiver1.recv::<()>().unwrap(); 133 | 134 | let channel = T::forward_from(sender1, receiver1); 135 | 136 | sender2.send(channel).unwrap(); 137 | }); 138 | 139 | receiver2 140 | } 141 | } 142 | 143 | impl ForwardChannel for Value 144 | where 145 | T: Send + 'static, 146 | T: Serialize + for<'de> Deserialize<'de>, 147 | { 148 | fn forward_to( 149 | self, 150 | sender1: OpaqueSender, 151 | _receiver1: OpaqueReceiver, 152 | ) 153 | { 154 | let Value(payload) = self; 155 | 156 | sender1.send(payload); 157 | } 158 | 159 | fn forward_from( 160 | _sender1: OpaqueSender, 161 | receiver1: OpaqueReceiver, 162 | ) -> Self 163 | { 164 | let payload = receiver1.recv().unwrap(); 165 | 166 | Value(payload) 167 | } 168 | } 169 | 170 | impl ForwardChannel for (Value, C) 171 | where 172 | T: Send + 'static, 173 | T: Serialize + for<'de> Deserialize<'de>, 174 | C: ForwardChannel, 175 | { 176 | fn forward_to( 177 | self, 178 | sender1: OpaqueSender, 179 | receiver1: OpaqueReceiver, 180 | ) 181 | { 182 | let (Value(payload), channel) = self; 183 | 184 | task::spawn_blocking(move || { 185 | sender1.send(payload); 186 | 187 | channel.forward_to(sender1, receiver1) 188 | }); 189 | } 190 | 191 | fn forward_from( 192 | sender1: OpaqueSender, 193 | receiver1: OpaqueReceiver, 194 | ) -> Self 195 | { 196 | let payload = receiver1.recv().unwrap(); 197 | 198 | let channel = C::forward_from(sender1, receiver1); 199 | 200 | (Value(payload), channel) 201 | } 202 | } 203 | 204 | impl ForwardChannel for App<'static, F, X> 205 | where 206 | X: 'static, 207 | F: 'static, 208 | F: TypeApp<'static, X, Applied = T>, 209 | T: ForwardChannel, 210 | { 211 | fn forward_to( 212 | self, 213 | sender: OpaqueSender, 214 | receiver: OpaqueReceiver, 215 | ) 216 | { 217 | self.get_applied().forward_to(sender, receiver) 218 | } 219 | 220 | fn forward_from( 221 | sender: OpaqueSender, 222 | receiver: OpaqueReceiver, 223 | ) -> Self 224 | { 225 | App::new(T::forward_from(sender, receiver)) 226 | } 227 | } 228 | 229 | impl ForwardChannel for AppSum<'static, Row, F> 230 | where 231 | F: TyCon, 232 | F: Send + 'static, 233 | Row: 'static, 234 | Row: SumApp<'static, F, Applied = T>, 235 | T: ForwardChannel, 236 | { 237 | fn forward_to( 238 | self, 239 | sender: OpaqueSender, 240 | receiver: OpaqueReceiver, 241 | ) 242 | { 243 | self.get_sum().forward_to(sender, receiver) 244 | } 245 | 246 | fn forward_from( 247 | sender: OpaqueSender, 248 | receiver: OpaqueReceiver, 249 | ) -> Self 250 | { 251 | AppSum::new(T::forward_from(sender, receiver)) 252 | } 253 | } 254 | 255 | impl ForwardChannel for Sum 256 | where 257 | A: ForwardChannel, 258 | B: ForwardChannel, 259 | { 260 | fn forward_to( 261 | self, 262 | sender1: OpaqueSender, 263 | receiver1: OpaqueReceiver, 264 | ) 265 | { 266 | match self { 267 | Sum::Inl(a) => { 268 | sender1.send(true); 269 | 270 | a.forward_to(sender1, receiver1) 271 | } 272 | Sum::Inr(b) => { 273 | sender1.send(false); 274 | 275 | b.forward_to(sender1, receiver1) 276 | } 277 | } 278 | } 279 | 280 | fn forward_from( 281 | sender1: OpaqueSender, 282 | receiver1: OpaqueReceiver, 283 | ) -> Self 284 | { 285 | if receiver1.recv().unwrap() { 286 | Sum::Inl(A::forward_from(sender1, receiver1)) 287 | } else { 288 | Sum::Inr(B::forward_from(sender1, receiver1)) 289 | } 290 | } 291 | } 292 | 293 | impl ForwardChannel for Bottom 294 | { 295 | fn forward_to( 296 | self, 297 | _: OpaqueSender, 298 | _: OpaqueReceiver, 299 | ) 300 | { 301 | match self {} 302 | } 303 | 304 | fn forward_from( 305 | _: OpaqueSender, 306 | receiver1: OpaqueReceiver, 307 | ) -> Self 308 | { 309 | receiver1.recv().unwrap() 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/channel/mod.rs: -------------------------------------------------------------------------------- 1 | mod functions; 2 | mod impls; 3 | mod traits; 4 | mod types; 5 | 6 | pub use functions::*; 7 | pub use traits::*; 8 | pub use types::*; 9 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/channel/traits.rs: -------------------------------------------------------------------------------- 1 | use super::types::{ 2 | OpaqueReceiver, 3 | OpaqueSender, 4 | }; 5 | 6 | pub trait ForwardChannel: Send + 'static 7 | { 8 | fn forward_to( 9 | self, 10 | sender: OpaqueSender, 11 | receiver: OpaqueReceiver, 12 | ); 13 | 14 | fn forward_from( 15 | sender: OpaqueSender, 16 | receiver: OpaqueReceiver, 17 | ) -> Self; 18 | } 19 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/channel/types.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | marker::PhantomData, 3 | mem, 4 | ops::DerefMut, 5 | }; 6 | use std::sync::{ 7 | Arc, 8 | Mutex, 9 | }; 10 | 11 | use ipc_channel::ipc; 12 | use serde::{ 13 | self, 14 | Deserialize, 15 | Serialize, 16 | }; 17 | use tokio::sync::{ 18 | mpsc, 19 | oneshot, 20 | Mutex as AsyncMutex, 21 | }; 22 | 23 | pub struct Value(pub T); 24 | 25 | pub struct Sender(pub mpsc::UnboundedSender); 26 | 27 | pub struct Receiver(pub Arc>>); 28 | 29 | pub struct SenderOnce(pub oneshot::Sender); 30 | 31 | pub struct ReceiverOnce(pub oneshot::Receiver); 32 | 33 | #[derive(Clone, serde::Serialize, serde::Deserialize)] 34 | pub struct OpaqueReceiver(pub Arc>>); 35 | 36 | #[derive(Clone, serde::Serialize, serde::Deserialize)] 37 | pub struct OpaqueSender(pub Arc>>); 38 | 39 | #[derive(Clone, serde::Serialize, serde::Deserialize)] 40 | pub struct IpcSender 41 | { 42 | pub sender: OpaqueSender, 43 | pub phantom: PhantomData, 44 | } 45 | 46 | #[derive(Clone, serde::Serialize, serde::Deserialize)] 47 | pub struct IpcReceiver 48 | { 49 | pub receiver: OpaqueReceiver, 50 | pub phantom: PhantomData, 51 | } 52 | 53 | // TODO: Define proper error type 54 | #[derive(Debug)] 55 | pub struct SendError(pub String); 56 | 57 | impl Receiver 58 | { 59 | pub async fn recv(&self) -> Option 60 | { 61 | self.0.lock().await.recv().await 62 | } 63 | } 64 | 65 | impl SenderOnce 66 | { 67 | pub fn send( 68 | self, 69 | msg: T, 70 | ) -> Result<(), SendError> 71 | { 72 | self 73 | .0 74 | .send(msg) 75 | .map_err(|_| SendError(String::from("failed to send"))) 76 | } 77 | } 78 | 79 | impl ReceiverOnce 80 | { 81 | pub async fn recv(self) -> Result 82 | { 83 | self.0.await 84 | } 85 | 86 | pub async fn close(mut self) 87 | { 88 | self.0.close() 89 | } 90 | } 91 | 92 | impl IpcSender 93 | where 94 | T: for<'de> Deserialize<'de> + Serialize, 95 | { 96 | pub fn send( 97 | &self, 98 | data: T, 99 | ) 100 | { 101 | self.sender.send(data) 102 | } 103 | } 104 | 105 | impl IpcReceiver 106 | where 107 | T: for<'de> Deserialize<'de> + Serialize, 108 | { 109 | pub fn recv(&self) -> Option 110 | { 111 | self.receiver.recv() 112 | } 113 | } 114 | 115 | impl OpaqueSender 116 | { 117 | pub fn send( 118 | &self, 119 | val: T, 120 | ) where 121 | T: for<'de> Deserialize<'de> + Serialize, 122 | { 123 | let mut cell = self.0.lock().unwrap(); 124 | 125 | let sender1 = mem::take(cell.deref_mut()).unwrap(); 126 | 127 | let sender2 = sender1.to(); 128 | 129 | sender2.send(val).unwrap(); 130 | 131 | let _ = mem::replace(cell.deref_mut(), Some(sender2.to_opaque())); 132 | } 133 | } 134 | 135 | impl OpaqueReceiver 136 | { 137 | pub fn recv(&self) -> Option 138 | where 139 | T: for<'de> Deserialize<'de> + Serialize, 140 | { 141 | let mut cell = self.0.lock().unwrap(); 142 | 143 | let receiver1 = mem::take(cell.deref_mut()).unwrap(); 144 | 145 | let receiver2 = receiver1.to(); 146 | 147 | let val = receiver2.recv().ok(); 148 | 149 | let _ = mem::replace(cell.deref_mut(), Some(receiver2.to_opaque())); 150 | 151 | val 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/context/impls.rs: -------------------------------------------------------------------------------- 1 | use super::traits::*; 2 | use crate::internal::{ 3 | base::protocol::{ 4 | ClientEndpoint, 5 | Protocol, 6 | }, 7 | functional::nat::{ 8 | S, 9 | Z, 10 | }, 11 | }; 12 | 13 | impl SealedSlot for A where A: Protocol {} 14 | 15 | impl Slot for A 16 | where 17 | A: Protocol, 18 | { 19 | type Endpoint = ClientEndpoint; 20 | } 21 | 22 | impl SealedSlot for Empty {} 23 | 24 | impl Slot for Empty 25 | { 26 | type Endpoint = (); 27 | } 28 | 29 | impl ContextLens<(A1, C), A1, A2> for Z 30 | where 31 | A1: Slot, 32 | A2: Slot, 33 | C: Context, 34 | { 35 | type Deleted = C; 36 | type Target = (A2, C); 37 | 38 | fn extract_source( 39 | ctx: (A1::Endpoint, C::Endpoints) 40 | ) -> (A1::Endpoint, C::Endpoints) 41 | { 42 | ctx 43 | } 44 | 45 | fn insert_target( 46 | p: A2::Endpoint, 47 | r: C::Endpoints, 48 | ) -> (A2::Endpoint, C::Endpoints) 49 | { 50 | (p, r) 51 | } 52 | } 53 | 54 | impl ContextLens<(B, C), A1, A2> for S 55 | where 56 | B: Slot, 57 | A1: Slot, 58 | A2: Slot, 59 | C: Context, 60 | N: ContextLens, 61 | { 62 | type Deleted = (B, N::Deleted); 63 | type Target = (B, N::Target); 64 | 65 | fn extract_source( 66 | (p, r1): (B::Endpoint, C::Endpoints) 67 | ) -> ( 68 | A1::Endpoint, 69 | (B::Endpoint, ::Endpoints), 70 | ) 71 | { 72 | let (q, r2) = N::extract_source(r1); 73 | 74 | (q, (p, r2)) 75 | } 76 | 77 | fn insert_target( 78 | q: A2::Endpoint, 79 | (p, r1): (B::Endpoint, ::Endpoints), 80 | ) -> (B::Endpoint, ::Endpoints) 81 | { 82 | let r2 = N::insert_target(q, r1); 83 | 84 | (p, r2) 85 | } 86 | } 87 | 88 | impl SealedContext for () {} 89 | 90 | impl Context for () 91 | { 92 | type Endpoints = (); 93 | type Length = Z; 94 | } 95 | 96 | impl SealedEmptyContext for () {} 97 | 98 | impl EmptyContext for () 99 | { 100 | fn empty_values() {} 101 | } 102 | 103 | impl SealedEmptyContext for (Empty, R) where R: EmptyContext {} 104 | 105 | impl EmptyContext for (Empty, R) 106 | where 107 | R: EmptyContext, 108 | { 109 | fn empty_values() -> ((), R::Endpoints) 110 | { 111 | ((), R::empty_values()) 112 | } 113 | } 114 | 115 | impl SealedContext for (P, R) {} 116 | 117 | impl Context for (P, R) 118 | where 119 | P: Slot, 120 | R: Context, 121 | { 122 | type Endpoints = (P::Endpoint, R::Endpoints); 123 | type Length = S; 124 | } 125 | 126 | impl AppendContext for () 127 | { 128 | type Appended = R; 129 | 130 | fn append_context( 131 | _: (), 132 | r: ::Endpoints, 133 | ) -> ::Endpoints 134 | { 135 | r 136 | } 137 | 138 | fn split_context( 139 | r: ::Endpoints 140 | ) -> ((), ::Endpoints) 141 | { 142 | ((), r) 143 | } 144 | } 145 | 146 | impl AppendContext for (P, R) 147 | where 148 | P: Slot, 149 | R: Context, 150 | S: Context, 151 | R: AppendContext, 152 | { 153 | type Appended = (P, >::Appended); 154 | 155 | fn append_context( 156 | (p, r): (P::Endpoint, R::Endpoints), 157 | s: ::Endpoints, 158 | ) -> (

::Endpoint, ::Endpoints) 159 | { 160 | (p, >::append_context(r, s)) 161 | } 162 | 163 | fn split_context( 164 | (p, r): (P::Endpoint, ::Endpoints) 165 | ) -> (<(P, R) as Context>::Endpoints, ::Endpoints) 166 | { 167 | let (r2, s) = R::split_context(r); 168 | 169 | ((p, r2), s) 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/context/mod.rs: -------------------------------------------------------------------------------- 1 | mod impls; 2 | mod traits; 3 | 4 | pub use traits::*; 5 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/context/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::functional::nat::Nat; 2 | 3 | pub struct Empty; 4 | 5 | pub trait SealedContext {} 6 | 7 | pub trait Context: SealedContext + Send + 'static 8 | { 9 | type Endpoints: Sized + Send; 10 | 11 | type Length: Nat; 12 | } 13 | 14 | pub trait SealedEmptyContext {} 15 | 16 | pub trait EmptyContext: SealedEmptyContext + Context 17 | { 18 | fn empty_values() -> ::Endpoints; 19 | } 20 | 21 | pub trait AppendContext: Context 22 | where 23 | R: Context, 24 | { 25 | type Appended: Context; 26 | 27 | fn append_context( 28 | channels1: ::Endpoints, 29 | channels2: ::Endpoints, 30 | ) -> ::Endpoints; 31 | 32 | fn split_context( 33 | channels: ::Endpoints 34 | ) -> (::Endpoints, ::Endpoints); 35 | } 36 | 37 | pub trait SealedSlot {} 38 | 39 | pub trait Slot: SealedSlot + Send + 'static 40 | { 41 | type Endpoint: Send; 42 | } 43 | 44 | pub trait ContextLens: Send + 'static 45 | where 46 | C: Context, 47 | A1: Slot, 48 | A2: Slot, 49 | { 50 | type Deleted: Context; 51 | 52 | type Target: Context; 53 | 54 | fn extract_source( 55 | channels: C::Endpoints 56 | ) -> (A1::Endpoint, ::Endpoints); 57 | 58 | fn insert_target( 59 | receiver: A2::Endpoint, 60 | channels: ::Endpoints, 61 | ) -> ::Endpoints; 62 | } 63 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/mod.rs: -------------------------------------------------------------------------------- 1 | mod channel; 2 | mod context; 3 | mod protocol; 4 | mod rec; 5 | mod session; 6 | mod shared; 7 | 8 | pub mod public; 9 | 10 | #[doc(inline)] 11 | pub use self::{ 12 | channel::{ 13 | ipc_channel, 14 | once_channel, 15 | opaque_channel, 16 | unbounded, 17 | ForwardChannel, 18 | IpcReceiver, 19 | IpcSender, 20 | OpaqueReceiver, 21 | OpaqueSender, 22 | Receiver, 23 | ReceiverOnce, 24 | Sender, 25 | SenderOnce, 26 | Value, 27 | }, 28 | context::{ 29 | AppendContext, 30 | Context, 31 | ContextLens, 32 | Empty, 33 | EmptyContext, 34 | Slot, 35 | }, 36 | protocol::{ 37 | ClientEndpoint, 38 | ClientEndpointF, 39 | Protocol, 40 | ProviderEndpoint, 41 | ProviderEndpointF, 42 | SealedProtocol, 43 | SealedSharedProtocol, 44 | SharedProtocol, 45 | }, 46 | rec::{ 47 | fix, 48 | unfix, 49 | HasRecApp, 50 | Rec, 51 | RecApp, 52 | RecEndpoint, 53 | RecRow, 54 | RecX, 55 | Release, 56 | SharedRecApp, 57 | SharedRecRow, 58 | }, 59 | session::{ 60 | unsafe_create_session, 61 | unsafe_run_session, 62 | PartialSession, 63 | Session, 64 | }, 65 | shared::{ 66 | unsafe_create_shared_channel, 67 | unsafe_create_shared_session, 68 | unsafe_forward_shared_channel, 69 | unsafe_receive_shared_channel, 70 | unsafe_run_shared_session, 71 | SharedChannel, 72 | SharedSession, 73 | }, 74 | }; 75 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/protocol/impls.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | 6 | use super::{ 7 | traits::*, 8 | types::*, 9 | }; 10 | use crate::internal::functional::{ 11 | nat::*, 12 | type_app::{ 13 | TyCon, 14 | TypeApp, 15 | }, 16 | }; 17 | 18 | impl TyCon for ProviderEndpointF {} 19 | 20 | impl TyCon for ClientEndpointF {} 21 | 22 | impl<'a, A: Protocol> TypeApp<'a, A> for ProviderEndpointF 23 | { 24 | type Applied = A::ProviderEndpoint; 25 | } 26 | 27 | impl<'a, A: Protocol> TypeApp<'a, A> for ClientEndpointF 28 | { 29 | type Applied = A::ClientEndpoint; 30 | } 31 | 32 | impl SealedProtocol for Z {} 33 | 34 | impl Protocol for Z 35 | { 36 | type ClientEndpoint = (); 37 | type ProviderEndpoint = (); 38 | 39 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 40 | { 41 | ((), ()) 42 | } 43 | 44 | fn forward( 45 | _client_end: Self::ClientEndpoint, 46 | _provider_end: Self::ProviderEndpoint, 47 | ) -> Pin + Send + 'static>> 48 | { 49 | Box::pin(async {}) 50 | } 51 | } 52 | 53 | impl SealedProtocol for S {} 54 | 55 | impl Protocol for S 56 | where 57 | N: Protocol, 58 | { 59 | type ClientEndpoint = (); 60 | type ProviderEndpoint = (); 61 | 62 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 63 | { 64 | ((), ()) 65 | } 66 | 67 | fn forward( 68 | _client_end: Self::ClientEndpoint, 69 | _provider_end: Self::ProviderEndpoint, 70 | ) -> Pin + Send + 'static>> 71 | { 72 | Box::pin(async {}) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/protocol/mod.rs: -------------------------------------------------------------------------------- 1 | mod impls; 2 | mod traits; 3 | mod types; 4 | 5 | pub use traits::*; 6 | pub use types::*; 7 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/protocol/traits.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | 6 | pub trait SealedProtocol {} 7 | 8 | pub trait Protocol: SealedProtocol + Send + 'static 9 | { 10 | type ProviderEndpoint: Send + 'static; 11 | type ClientEndpoint: Send + 'static; 12 | 13 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint); 14 | 15 | fn forward( 16 | client_end: Self::ClientEndpoint, 17 | provider_end: Self::ProviderEndpoint, 18 | ) -> Pin + Send + 'static>>; 19 | } 20 | 21 | pub trait SealedSharedProtocol {} 22 | 23 | pub trait SharedProtocol: SealedSharedProtocol + Send + 'static {} 24 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/protocol/types.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::functional::App; 2 | 3 | pub struct ProviderEndpointF; 4 | 5 | pub struct ClientEndpointF; 6 | 7 | pub type ProviderEndpoint = App<'static, ProviderEndpointF, A>; 8 | 9 | pub type ClientEndpoint = App<'static, ClientEndpointF, A>; 10 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/public.rs: -------------------------------------------------------------------------------- 1 | #[doc(inline)] 2 | pub use super::{ 3 | AppendContext, 4 | Context, 5 | Empty, 6 | EmptyContext, 7 | PartialSession, 8 | Protocol, 9 | Rec, 10 | RecX, 11 | Release, 12 | Session, 13 | SharedChannel, 14 | SharedProtocol, 15 | SharedSession, 16 | Slot, 17 | }; 18 | 19 | pub trait ContextLens: super::ContextLens 20 | where 21 | C: Context, 22 | A1: Slot, 23 | A2: Slot, 24 | { 25 | } 26 | 27 | impl ContextLens for N 28 | where 29 | C: Context, 30 | A1: Slot, 31 | A2: Slot, 32 | N: super::ContextLens, 33 | { 34 | } 35 | 36 | pub trait RecApp: super::RecApp {} 37 | 38 | impl RecApp for X where X: super::RecApp {} 39 | 40 | pub trait SharedRecApp: super::SharedRecApp {} 41 | 42 | impl SharedRecApp for S where S: super::SharedRecApp {} 43 | 44 | pub trait HasRecApp: super::HasRecApp {} 45 | 46 | impl HasRecApp for X where X: super::HasRecApp {} 47 | 48 | pub trait ForwardChannel: super::ForwardChannel {} 49 | 50 | impl ForwardChannel for A where A: super::ForwardChannel {} 51 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/rec/functions.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | traits::RecApp, 3 | types::RecX, 4 | }; 5 | 6 | pub fn fix(x: F::Applied) -> RecX 7 | where 8 | C: Send + 'static, 9 | F: Send + 'static, 10 | F: RecApp<(RecX, C)>, 11 | { 12 | RecX { unfix: Box::new(x) } 13 | } 14 | 15 | pub fn unfix(x: RecX) -> F::Applied 16 | where 17 | C: Send + 'static, 18 | F: Send + 'static, 19 | F: RecApp<(RecX, C)>, 20 | { 21 | *x.unfix.get_applied() 22 | } 23 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/rec/impls.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | 6 | use super::{ 7 | traits::{ 8 | HasRecApp, 9 | HasRecEndpoint, 10 | RecApp, 11 | SharedRecApp, 12 | }, 13 | types::{ 14 | RecEndpoint, 15 | RecRow, 16 | RecX, 17 | Release, 18 | SharedRecRow, 19 | }, 20 | }; 21 | use crate::internal::{ 22 | base::{ 23 | channel::{ 24 | once_channel, 25 | ReceiverOnce, 26 | SenderOnce, 27 | }, 28 | protocol::{ 29 | Protocol, 30 | SealedProtocol, 31 | }, 32 | }, 33 | functional::*, 34 | }; 35 | 36 | impl HasRecApp for T 37 | where 38 | F: 'static, 39 | A: 'static, 40 | T: Send + 'static, 41 | F: RecApp, 42 | { 43 | fn get_applied(self: Box) -> Box 44 | { 45 | self 46 | } 47 | } 48 | 49 | impl RecApp for RecX<(), F> 50 | where 51 | C: Send, 52 | F: RecApp<(RecX, C)>, 53 | { 54 | type Applied = RecX; 55 | } 56 | 57 | impl RecApp<(A, C)> for Z 58 | where 59 | A: Send, 60 | C: Send, 61 | { 62 | type Applied = A; 63 | } 64 | 65 | impl RecApp<(A, C)> for S 66 | where 67 | N: Send, 68 | C: Send, 69 | A: Send, 70 | N: RecApp, 71 | { 72 | type Applied = N::Applied; 73 | } 74 | 75 | impl RecApp for () 76 | { 77 | type Applied = (); 78 | } 79 | 80 | impl RecApp for (X, Y) 81 | where 82 | X: RecApp, 83 | Y: RecApp, 84 | { 85 | type Applied = (X::Applied, Y::Applied); 86 | } 87 | 88 | impl SharedRecApp for Release 89 | { 90 | type Applied = X; 91 | } 92 | 93 | impl SharedRecApp for () 94 | { 95 | type Applied = (); 96 | } 97 | 98 | impl SharedRecApp for (P, Q) 99 | where 100 | P: SharedRecApp, 101 | Q: SharedRecApp, 102 | { 103 | type Applied = (P::Applied, Q::Applied); 104 | } 105 | 106 | impl SharedRecApp for RecX<(), F> 107 | where 108 | F: SharedRecApp, 109 | { 110 | type Applied = RecX<(), F::Applied>; 111 | } 112 | 113 | impl HasRecEndpoint for E 114 | where 115 | E: Send + 'static, 116 | F: RecApp, 117 | F::Applied: Protocol, 118 | { 119 | fn get_applied(self: Box) -> Box 120 | { 121 | self 122 | } 123 | } 124 | 125 | impl SealedProtocol for RecX {} 126 | 127 | impl Protocol for RecX 128 | where 129 | C: Send + 'static, 130 | F: Protocol, 131 | F: RecApp<(RecX, C)>, 132 | { 133 | type ClientEndpoint = ReceiverOnce, C)>>; 134 | type ProviderEndpoint = SenderOnce, C)>>; 135 | 136 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 137 | { 138 | once_channel() 139 | } 140 | 141 | fn forward( 142 | client_end: Self::ClientEndpoint, 143 | provider_end: Self::ProviderEndpoint, 144 | ) -> Pin + Send + 'static>> 145 | { 146 | Box::pin(async { 147 | let endpoint = client_end.recv().await.unwrap(); 148 | provider_end.send(endpoint).unwrap(); 149 | }) 150 | } 151 | } 152 | 153 | impl SealedProtocol for Release {} 154 | 155 | impl Protocol for Release 156 | { 157 | type ClientEndpoint = (); 158 | type ProviderEndpoint = (); 159 | 160 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 161 | { 162 | ((), ()) 163 | } 164 | 165 | fn forward( 166 | _client_end: Self::ClientEndpoint, 167 | _provider_end: Self::ProviderEndpoint, 168 | ) -> Pin + Send + 'static>> 169 | { 170 | Box::pin(async {}) 171 | } 172 | } 173 | 174 | impl ToRow for RecRow 175 | where 176 | R: Send, 177 | Row1: ToRow, 178 | Row2: RecApp, 179 | Row3: RowCon, 180 | { 181 | type Row = Row3; 182 | } 183 | 184 | impl ToRow for SharedRecRow 185 | where 186 | R: Send, 187 | Row1: ToRow, 188 | Row2: SharedRecApp, 189 | Row3: RowCon, 190 | { 191 | type Row = Row3; 192 | } 193 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/rec/mod.rs: -------------------------------------------------------------------------------- 1 | mod functions; 2 | mod impls; 3 | mod traits; 4 | mod types; 5 | 6 | pub use functions::*; 7 | pub use traits::*; 8 | pub use types::*; 9 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/rec/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::base::protocol::Protocol; 2 | 3 | pub trait RecApp: Sized 4 | { 5 | type Applied: Send; 6 | } 7 | 8 | pub trait HasRecApp: Send 9 | { 10 | fn get_applied(self: Box) -> Box 11 | where 12 | F: RecApp; 13 | } 14 | 15 | pub trait SharedRecApp 16 | { 17 | type Applied; 18 | } 19 | 20 | pub trait HasRecEndpoint: Send + 'static 21 | { 22 | fn get_applied( 23 | self: Box 24 | ) -> Box<::ClientEndpoint> 25 | where 26 | F: RecApp, 27 | F::Applied: Protocol; 28 | } 29 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/rec/types.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | use super::{ 4 | HasRecApp, 5 | HasRecEndpoint, 6 | }; 7 | 8 | pub struct RecX 9 | { 10 | pub unfix: Box, C)>>, 11 | } 12 | 13 | pub type Rec = RecX<(), F>; 14 | 15 | pub enum Release {} 16 | 17 | pub struct RecRow 18 | { 19 | phantom: PhantomData<(R, Row)>, 20 | } 21 | 22 | pub struct SharedRecRow 23 | { 24 | phantom: PhantomData<(R, Row)>, 25 | } 26 | 27 | pub struct RecEndpoint 28 | { 29 | pub applied: Box>, 30 | } 31 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/session/functions.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | 6 | use tokio::task; 7 | 8 | use super::types::*; 9 | use crate::internal::{ 10 | base::{ 11 | context::Context, 12 | protocol::{ 13 | Protocol, 14 | ProviderEndpoint, 15 | }, 16 | }, 17 | functional::App, 18 | }; 19 | 20 | pub fn unsafe_create_session( 21 | executor: Cont 22 | ) -> PartialSession 23 | where 24 | A: Protocol, 25 | C: Context, 26 | Cont: FnOnce(C::Endpoints, A::ProviderEndpoint) -> Fut + Send + 'static, 27 | Fut: Future + Send, 28 | { 29 | let executor2: Box< 30 | dyn FnOnce( 31 | C::Endpoints, 32 | ProviderEndpoint, 33 | ) -> Pin + Send>> 34 | + Send, 35 | > = Box::new(move |ctx, provider_end| { 36 | Box::pin(async { 37 | // run the executor as a separate async task to avoid stack overflow 38 | // due to overly deeply nested futures. 39 | task::spawn(async move { 40 | executor(ctx, provider_end.get_applied()).await; 41 | }) 42 | .await 43 | .unwrap(); 44 | }) 45 | }); 46 | 47 | PartialSession { 48 | executor: executor2, 49 | } 50 | } 51 | 52 | pub async fn unsafe_run_session( 53 | session: PartialSession, 54 | ctx: C::Endpoints, 55 | provider_end: A::ProviderEndpoint, 56 | ) where 57 | A: Protocol, 58 | C: Context, 59 | { 60 | // task::spawn(async move { 61 | (session.executor)(ctx, App::new(provider_end)).await; 62 | // }) 63 | // .await 64 | // .unwrap(); 65 | } 66 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/session/mod.rs: -------------------------------------------------------------------------------- 1 | mod functions; 2 | mod types; 3 | 4 | pub use functions::*; 5 | pub use types::*; 6 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/session/types.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | 6 | use crate::internal::base::{ 7 | context::Context, 8 | protocol::{ 9 | Protocol, 10 | ProviderEndpoint, 11 | }, 12 | }; 13 | 14 | pub type Session

= PartialSession<(), P>; 15 | 16 | pub struct PartialSession 17 | where 18 | A: Protocol, 19 | C: Context, 20 | { 21 | pub(crate) executor: Box< 22 | dyn FnOnce( 23 | C::Endpoints, 24 | ProviderEndpoint, 25 | ) -> Pin + Send>> 26 | + Send, 27 | >, 28 | } 29 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/shared/functions.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | 6 | use tokio::task; 7 | 8 | use super::types::*; 9 | use crate::internal::base::{ 10 | channel::*, 11 | protocol::*, 12 | }; 13 | 14 | pub async fn unsafe_forward_shared_channel( 15 | channel: SharedChannel, 16 | receiver: Receiver<(SenderOnce<()>, SenderOnce)>, 17 | ) where 18 | S: SharedProtocol, 19 | { 20 | while let Some(senders) = receiver.recv().await { 21 | channel.endpoint.send(senders).unwrap(); 22 | } 23 | } 24 | 25 | pub async fn unsafe_run_shared_session( 26 | session: SharedSession, 27 | receiver: Receiver<(SenderOnce<()>, SenderOnce)>, 28 | ) where 29 | S: SharedProtocol, 30 | { 31 | (session.executor)(receiver).await; 32 | } 33 | 34 | pub fn unsafe_create_shared_session( 35 | executor1: impl FnOnce(Receiver<(SenderOnce<()>, SenderOnce)>) -> Fut 36 | + Send 37 | + 'static 38 | ) -> SharedSession 39 | where 40 | S: SharedProtocol, 41 | Fut: Future + Send, 42 | { 43 | let executor: Box< 44 | dyn FnOnce( 45 | Receiver<(SenderOnce<()>, SenderOnce)>, 46 | ) -> Pin + Send>> 47 | + Send, 48 | > = Box::new(move |receiver| { 49 | Box::pin(async { 50 | task::spawn(async move { 51 | executor1(receiver).await; 52 | }) 53 | .await 54 | .unwrap(); 55 | }) 56 | }); 57 | 58 | SharedSession { executor } 59 | } 60 | 61 | pub fn unsafe_create_shared_channel( 62 | ) -> (SharedChannel, Receiver<(SenderOnce<()>, SenderOnce)>) 63 | where 64 | S: SharedProtocol, 65 | { 66 | let (sender, receiver) = unbounded(); 67 | 68 | (SharedChannel { endpoint: sender }, receiver) 69 | } 70 | 71 | pub fn unsafe_receive_shared_channel( 72 | session: SharedChannel 73 | ) -> (ReceiverOnce<()>, ReceiverOnce) 74 | where 75 | S: SharedProtocol, 76 | { 77 | let (sender1, receiver1) = once_channel::<()>(); 78 | 79 | let (sender2, receiver2) = once_channel::(); 80 | 81 | session.endpoint.send((sender1, sender2)).unwrap(); 82 | 83 | (receiver1, receiver2) 84 | } 85 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/shared/mod.rs: -------------------------------------------------------------------------------- 1 | mod functions; 2 | mod serialize; 3 | mod types; 4 | 5 | pub use functions::*; 6 | pub use types::*; 7 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/shared/serialize.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | use tokio::task; 4 | 5 | use super::types::*; 6 | use crate::internal::base::{ 7 | channel::*, 8 | protocol::*, 9 | }; 10 | 11 | #[derive(serde::Serialize, serde::Deserialize)] 12 | pub struct SerializedSharedChannel 13 | where 14 | S: SharedProtocol, 15 | { 16 | acquire_sender: IpcSender<()>, 17 | acquire_receiver: IpcReceiver<()>, 18 | linear_sender: OpaqueSender, 19 | linear_receiver: OpaqueReceiver, 20 | phantom: PhantomData, 21 | } 22 | 23 | impl Clone for SerializedSharedChannel 24 | where 25 | S: SharedProtocol, 26 | { 27 | fn clone(&self) -> Self 28 | { 29 | SerializedSharedChannel { 30 | acquire_sender: self.acquire_sender.clone(), 31 | acquire_receiver: self.acquire_receiver.clone(), 32 | linear_sender: self.linear_sender.clone(), 33 | linear_receiver: self.linear_receiver.clone(), 34 | phantom: PhantomData, 35 | } 36 | } 37 | } 38 | 39 | fn serialize_shared_channel( 40 | channel: SharedChannel 41 | ) -> SerializedSharedChannel 42 | where 43 | S: SharedProtocol + ForwardChannel, 44 | { 45 | let (sender1, receiver1) = ipc_channel::<()>(); 46 | 47 | let (sender2, receiver2) = ipc_channel::<()>(); 48 | 49 | let (sender3, receiver3) = opaque_channel(); 50 | 51 | let (sender4, receiver4) = opaque_channel(); 52 | 53 | task::spawn(async move { 54 | loop { 55 | let receiver1 = receiver1.clone(); 56 | 57 | let signal = task::spawn_blocking(move || receiver1.recv()) 58 | .await 59 | .unwrap(); 60 | 61 | match signal { 62 | Some(()) => { 63 | let (sender5, receiver5) = once_channel::<()>(); 64 | 65 | let (sender6, receiver6) = once_channel::(); 66 | 67 | { 68 | let channel = channel.clone(); 69 | 70 | let sender2 = sender2.clone(); 71 | 72 | let receiver3 = receiver3.clone(); 73 | 74 | let sender4 = sender4.clone(); 75 | 76 | debug!("[serialize_shared_channel] acquiring local shared channel"); 77 | 78 | channel.endpoint.send((sender5, sender6)).unwrap(); 79 | 80 | receiver5.recv().await.unwrap(); 81 | 82 | debug!("[serialize_shared_channel] acquired local shared channel"); 83 | 84 | sender2.send(()); 85 | 86 | receiver6.forward_to(sender4, receiver3); 87 | } 88 | } 89 | None => break, 90 | } 91 | } 92 | }); 93 | 94 | SerializedSharedChannel { 95 | acquire_sender: sender1, 96 | acquire_receiver: receiver2, 97 | linear_sender: sender3, 98 | linear_receiver: receiver4, 99 | phantom: PhantomData, 100 | } 101 | } 102 | 103 | fn deserialize_shared_channel( 104 | channel: SerializedSharedChannel 105 | ) -> SharedChannel 106 | where 107 | S: SharedProtocol + ForwardChannel + Send, 108 | { 109 | let (sender1, receiver1) = unbounded::<(SenderOnce<()>, SenderOnce)>(); 110 | 111 | task::spawn(async move { 112 | while let Some((sender2, sender3)) = receiver1.recv().await { 113 | debug!("[deserialize_shared_channel] acquiring remote shared channel"); 114 | 115 | channel.acquire_sender.send(()); 116 | 117 | let acquire_receiver = channel.acquire_receiver.clone(); 118 | 119 | task::spawn_blocking(move || { 120 | acquire_receiver.recv().unwrap(); 121 | }) 122 | .await 123 | .unwrap(); 124 | 125 | debug!("[deserialize_shared_channel] acquired remote shared channel"); 126 | 127 | sender2.send(()).unwrap(); 128 | 129 | let channel2 = channel.clone(); 130 | 131 | sender3.forward_to(channel2.linear_sender, channel2.linear_receiver); 132 | } 133 | }); 134 | 135 | SharedChannel { endpoint: sender1 } 136 | } 137 | 138 | impl serde::Serialize for SharedChannel 139 | where 140 | A: SharedProtocol + ForwardChannel, 141 | { 142 | fn serialize( 143 | &self, 144 | serializer: S, 145 | ) -> Result 146 | where 147 | S: serde::Serializer, 148 | { 149 | serialize_shared_channel(self.clone()).serialize(serializer) 150 | } 151 | } 152 | 153 | impl<'a, A> serde::Deserialize<'a> for SharedChannel 154 | where 155 | A: SharedProtocol + ForwardChannel, 156 | { 157 | fn deserialize(deserializer: D) -> Result 158 | where 159 | D: serde::Deserializer<'a>, 160 | { 161 | let channel = >::deserialize(deserializer)?; 162 | 163 | Ok(deserialize_shared_channel(channel)) 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/base/shared/types.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | 6 | use crate::internal::base::{ 7 | channel::*, 8 | protocol::*, 9 | }; 10 | 11 | pub struct SharedSession 12 | where 13 | S: SharedProtocol, 14 | { 15 | pub(crate) executor: Box< 16 | dyn FnOnce( 17 | Receiver<(SenderOnce<()>, SenderOnce)>, 18 | ) -> Pin + Send>> 19 | + Send, 20 | >, 21 | } 22 | 23 | pub struct SharedChannel 24 | where 25 | S: SharedProtocol, 26 | { 27 | pub(crate) endpoint: Sender<(SenderOnce<()>, SenderOnce)>, 28 | } 29 | 30 | impl Clone for SharedChannel 31 | where 32 | S: SharedProtocol, 33 | { 34 | fn clone(&self) -> Self 35 | { 36 | SharedChannel { 37 | endpoint: self.endpoint.clone(), 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/base.rs: -------------------------------------------------------------------------------- 1 | use super::type_app::*; 2 | 3 | // NaturalTransformation f1 f2 = forall x. f1 x -> f2 x 4 | pub trait NaturalTransformation<'a, F1, F2> 5 | where 6 | F1: TyCon, 7 | F2: TyCon, 8 | { 9 | fn lift( 10 | self, 11 | fa: App<'a, F1, A>, 12 | ) -> App<'a, F2, A>; 13 | } 14 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod base; 2 | pub mod nat; 3 | pub mod public; 4 | pub mod row; 5 | pub mod type_app; 6 | 7 | #[doc(inline)] 8 | pub use self::{ 9 | base::NaturalTransformation, 10 | nat::{ 11 | succ, 12 | Nat, 13 | S, 14 | Z, 15 | }, 16 | row::{ 17 | absurd, 18 | extract_choice, 19 | get_sum, 20 | get_sum_borrow, 21 | lift_sum, 22 | AppSum, 23 | Bottom, 24 | ChoiceSelector, 25 | FlattenSumApp, 26 | HasSumApp, 27 | Prism, 28 | RowCon, 29 | Sum, 30 | SumApp, 31 | SumFunctor, 32 | ToRow, 33 | }, 34 | type_app::{ 35 | App, 36 | HasTypeApp, 37 | TyCon, 38 | TypeApp, 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/nat.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | pub trait SealedNat {} 4 | 5 | pub trait Nat: SealedNat + Send + Copy + 'static 6 | { 7 | #[allow(non_upper_case_globals)] 8 | const Value: Self; 9 | 10 | fn nat() -> Self; 11 | } 12 | 13 | #[derive(Copy, Clone)] 14 | pub struct Z; 15 | 16 | #[derive(Copy, Clone)] 17 | pub struct S(pub PhantomData); 18 | 19 | impl SealedNat for Z {} 20 | 21 | impl Nat for Z 22 | { 23 | #[allow(non_upper_case_globals)] 24 | const Value: Z = Z; 25 | 26 | fn nat() -> Z 27 | { 28 | Z 29 | } 30 | } 31 | 32 | impl SealedNat for S where N: Nat {} 33 | 34 | impl Nat for S 35 | where 36 | N: Nat, 37 | { 38 | #[allow(non_upper_case_globals)] 39 | const Value: S = S(PhantomData); 40 | 41 | fn nat() -> S 42 | { 43 | S(PhantomData) 44 | } 45 | } 46 | 47 | pub fn succ(_: N) -> S 48 | { 49 | S(PhantomData) 50 | } 51 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/public.rs: -------------------------------------------------------------------------------- 1 | pub use super::{ 2 | absurd, 3 | extract_choice, 4 | get_sum, 5 | get_sum_borrow, 6 | lift_sum, 7 | succ, 8 | App, 9 | AppSum, 10 | Bottom, 11 | ChoiceSelector, 12 | FlattenSumApp, 13 | HasSumApp, 14 | HasTypeApp, 15 | Nat, 16 | NaturalTransformation, 17 | Prism, 18 | RowCon, 19 | Sum, 20 | SumApp, 21 | SumFunctor, 22 | ToRow, 23 | TyCon, 24 | TypeApp, 25 | S, 26 | Z, 27 | }; 28 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/row/impls.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | structs::*, 3 | traits::*, 4 | utils::*, 5 | }; 6 | use crate::internal::functional::{ 7 | base::*, 8 | nat::*, 9 | type_app::*, 10 | }; 11 | 12 | impl serde::Serialize for AppSum<'static, Row, F> 13 | where 14 | F: TyCon, 15 | Row: SumApp<'static, F>, 16 | Row::Applied: 17 | Send + 'static + serde::Serialize + for<'de> serde::Deserialize<'de>, 18 | { 19 | fn serialize( 20 | &self, 21 | serializer: S, 22 | ) -> Result 23 | where 24 | S: serde::Serializer, 25 | { 26 | let row: &Row::Applied = get_sum_borrow(self); 27 | 28 | row.serialize(serializer) 29 | } 30 | } 31 | 32 | impl<'a, Row, F, T> serde::Deserialize<'a> for AppSum<'a, Row, F> 33 | where 34 | F: TyCon, 35 | T: Send + 'static, 36 | Row: SumApp<'a, F, Applied = T>, 37 | T: serde::Serialize + for<'de> serde::Deserialize<'de>, 38 | { 39 | fn deserialize(deserializer: D) -> Result 40 | where 41 | D: serde::Deserializer<'a>, 42 | { 43 | let row = T::deserialize(deserializer)?; 44 | 45 | Ok(AppSum::new(row)) 46 | } 47 | } 48 | 49 | impl<'a, S, Row, F> HasSumApp<'a, Row, F> for S 50 | where 51 | F: TyCon, 52 | S: Send, 53 | Row: SumApp<'a, F, Applied = S>, 54 | { 55 | fn get_sum(self: Box) -> Box 56 | where 57 | F: TyCon, 58 | Row: SumApp<'a, F>, 59 | { 60 | self 61 | } 62 | 63 | fn get_sum_borrow(&self) -> &Row::Applied 64 | where 65 | F: TyCon, 66 | Row: SumApp<'a, F>, 67 | { 68 | self 69 | } 70 | } 71 | 72 | impl RowCon for (A, R) where R: RowCon {} 73 | 74 | impl RowCon for () {} 75 | 76 | impl ToRow for () 77 | { 78 | type Row = (); 79 | } 80 | 81 | impl ToRow for (A, R) 82 | where 83 | A: Send + 'static, 84 | R: RowCon, 85 | { 86 | type Row = (A, R); 87 | } 88 | 89 | impl<'a, F: 'a, A: 'a, R: 'a> SumApp<'a, F> for (A, R) 90 | where 91 | F: TyCon, 92 | R: RowCon, 93 | { 94 | type Applied = Sum, AppSum<'a, R, F>>; 95 | } 96 | 97 | impl<'a, F> SumApp<'a, F> for () 98 | where 99 | F: TyCon, 100 | { 101 | type Applied = Bottom; 102 | } 103 | 104 | impl<'a, F: 'a, A: 'a, R: 'a> FlattenSumApp<'a, F> for (A, R) 105 | where 106 | R: FlattenSumApp<'a, F>, 107 | F: TypeApp<'a, A>, 108 | { 109 | type FlattenApplied = Sum; 110 | 111 | fn unflatten_sum(row1: Self::FlattenApplied) -> Self::Applied 112 | { 113 | match row1 { 114 | Sum::Inl(field) => Sum::Inl(App::new(field)), 115 | Sum::Inr(row2) => { 116 | let row3 = R::unflatten_sum(row2); 117 | 118 | Sum::Inr(AppSum::new(row3)) 119 | } 120 | } 121 | } 122 | 123 | fn flatten_sum(row1: AppSum<'a, Self, F>) -> Self::FlattenApplied 124 | { 125 | match row1.get_sum() { 126 | Sum::Inl(field1) => { 127 | let field2 = field1.get_applied(); 128 | 129 | Sum::Inl(field2) 130 | } 131 | Sum::Inr(row2) => { 132 | let row3 = R::flatten_sum(row2); 133 | 134 | Sum::Inr(row3) 135 | } 136 | } 137 | } 138 | } 139 | 140 | impl<'a, F> FlattenSumApp<'a, F> for () 141 | where 142 | F: TyCon, 143 | { 144 | type FlattenApplied = Bottom; 145 | 146 | fn unflatten_sum(row: Self::FlattenApplied) -> Self::Applied 147 | { 148 | row 149 | } 150 | 151 | fn flatten_sum(row: AppSum) -> Self::FlattenApplied 152 | { 153 | row.get_sum() 154 | } 155 | } 156 | 157 | impl SumFunctor for () 158 | { 159 | fn lift_sum<'a, T: 'a, F1: 'a, F2: 'a>( 160 | _lift: T, 161 | row1: AppSum<'a, Self, F1>, 162 | ) -> AppSum<'a, Self, F2> 163 | where 164 | F1: TyCon, 165 | F2: TyCon, 166 | T: NaturalTransformation<'a, F1, F2>, 167 | { 168 | absurd(row1) 169 | } 170 | } 171 | 172 | impl SumFunctor for (A, R) 173 | where 174 | A: Send + 'static, 175 | R: SumFunctor, 176 | { 177 | fn lift_sum<'a, T: 'a, F1: 'a, F2: 'a>( 178 | lift: T, 179 | row1: AppSum<'a, Self, F1>, 180 | ) -> AppSum<'a, Self, F2> 181 | where 182 | F1: TyCon, 183 | F2: TyCon, 184 | T: NaturalTransformation<'a, F1, F2>, 185 | Self: 'a, 186 | { 187 | let row2 = row1.get_sum(); 188 | 189 | match row2 { 190 | Sum::Inl(fa1) => { 191 | let fa2 = lift.lift(fa1); 192 | 193 | AppSum::new(Sum::Inl(fa2)) 194 | } 195 | Sum::Inr(b) => AppSum::new(Sum::Inr(R::lift_sum::(lift, b))), 196 | } 197 | } 198 | } 199 | 200 | impl Prism<(A, R)> for ChoiceSelector 201 | where 202 | A: Send, 203 | R: RowCon, 204 | { 205 | type Elem = A; 206 | 207 | fn inject_elem<'a, F: 'a + Send>( 208 | t: App<'a, F, Self::Elem> 209 | ) -> AppSum<'a, (A, R), F> 210 | where 211 | F: TyCon, 212 | (A, R): 'a, 213 | { 214 | AppSum::new(Sum::Inl(t)) 215 | } 216 | 217 | fn extract_elem<'a, F: 'a + Send>( 218 | row: AppSum<'a, (A, R), F> 219 | ) -> Option> 220 | where 221 | F: TyCon, 222 | (A, R): 'a, 223 | { 224 | match row.get_sum() { 225 | Sum::Inl(e) => Some(e), 226 | Sum::Inr(_) => None, 227 | } 228 | } 229 | } 230 | 231 | impl Prism<(A, R)> for ChoiceSelector> 232 | where 233 | R: RowCon, 234 | A: Send + 'static, 235 | ChoiceSelector: Prism, 236 | { 237 | type Elem = as Prism>::Elem; 238 | 239 | fn inject_elem<'a, F: 'a + Send>( 240 | elem: App<'a, F, Self::Elem> 241 | ) -> AppSum<'a, (A, R), F> 242 | where 243 | F: TyCon, 244 | (A, R): 'a, 245 | { 246 | AppSum::new(Sum::Inr( as Prism>::inject_elem(elem))) 247 | } 248 | 249 | fn extract_elem<'a, F: 'a + Send>( 250 | row: AppSum<'a, (A, R), F> 251 | ) -> Option> 252 | where 253 | F: TyCon, 254 | (A, R): 'a, 255 | { 256 | match row.get_sum() { 257 | Sum::Inl(_) => None, 258 | Sum::Inr(rest) => as Prism>::extract_elem(rest), 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/row/mod.rs: -------------------------------------------------------------------------------- 1 | mod impls; 2 | mod structs; 3 | mod traits; 4 | mod utils; 5 | 6 | pub use impls::*; 7 | pub use structs::*; 8 | pub use traits::*; 9 | pub use utils::*; 10 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/row/structs.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | use serde::{ 4 | Deserialize, 5 | Serialize, 6 | }; 7 | 8 | use super::traits::*; 9 | use crate::internal::functional::type_app::*; 10 | 11 | #[derive(Copy, Clone, Serialize, Deserialize)] 12 | pub enum Bottom {} 13 | 14 | #[derive(Copy, Clone, Serialize, Deserialize)] 15 | pub enum Sum 16 | { 17 | Inl(A), 18 | Inr(B), 19 | } 20 | 21 | pub struct AppSum<'a, Row, F> 22 | { 23 | pub row: Box + 'a>, 24 | } 25 | 26 | pub struct ChoiceSelector 27 | { 28 | phantom: PhantomData, 29 | } 30 | 31 | impl<'a, Row, F> AppSum<'a, Row, F> 32 | where 33 | F: TyCon, 34 | Row: SumApp<'a, F>, 35 | { 36 | pub fn new(row: Row::Applied) -> AppSum<'a, Row, F> 37 | where 38 | F: TyCon, 39 | Row: SumApp<'a, F>, 40 | Row::Applied: Send, 41 | { 42 | AppSum { row: Box::new(row) } 43 | } 44 | 45 | pub fn get_sum(self) -> Row::Applied 46 | { 47 | *self.row.get_sum() 48 | } 49 | } 50 | 51 | impl ChoiceSelector 52 | { 53 | pub const fn new() -> ChoiceSelector 54 | { 55 | ChoiceSelector { 56 | phantom: PhantomData, 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/row/traits.rs: -------------------------------------------------------------------------------- 1 | use super::structs::*; 2 | use crate::internal::functional::{ 3 | base::*, 4 | type_app::*, 5 | }; 6 | 7 | pub trait RowCon: Sized {} 8 | 9 | pub trait ToRow 10 | { 11 | type Row; 12 | } 13 | 14 | pub trait SumApp<'a, F>: RowCon 15 | where 16 | F: TyCon, 17 | { 18 | type Applied: Sized + Send + 'a; 19 | } 20 | 21 | // Flatten the App wrappers in SumApp 22 | pub trait FlattenSumApp<'a, F>: SumApp<'a, F> 23 | where 24 | F: TyCon, 25 | { 26 | type FlattenApplied; 27 | 28 | fn unflatten_sum(row: Self::FlattenApplied) -> Self::Applied; 29 | 30 | fn flatten_sum(row: AppSum<'a, Self, F>) -> Self::FlattenApplied; 31 | } 32 | 33 | pub trait HasSumApp<'a, Row, F>: Send 34 | { 35 | fn get_sum(self: Box) -> Box 36 | where 37 | F: TyCon, 38 | Row: SumApp<'a, F>; 39 | 40 | fn get_sum_borrow<'b>(&'b self) -> &'b Row::Applied 41 | where 42 | F: TyCon, 43 | Row: SumApp<'a, F>; 44 | } 45 | 46 | pub trait SumFunctor: RowCon 47 | { 48 | fn lift_sum<'a, T: 'a, F1: 'a, F2: 'a>( 49 | lift: T, 50 | sum: AppSum<'a, Self, F1>, 51 | ) -> AppSum<'a, Self, F2> 52 | where 53 | F1: TyCon, 54 | F2: TyCon, 55 | T: NaturalTransformation<'a, F1, F2>, 56 | Self: 'a; 57 | } 58 | 59 | pub trait Prism 60 | where 61 | Row: RowCon, 62 | { 63 | type Elem; 64 | 65 | fn inject_elem<'a, F: 'a + Send>( 66 | elem: App<'a, F, Self::Elem> 67 | ) -> AppSum<'a, Row, F> 68 | where 69 | F: TyCon, 70 | Row: 'a; 71 | 72 | fn extract_elem<'a, F: 'a + Send>( 73 | row: AppSum<'a, Row, F> 74 | ) -> Option> 75 | where 76 | F: TyCon, 77 | Row: 'a; 78 | } 79 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/row/utils.rs: -------------------------------------------------------------------------------- 1 | use core::convert::Into; 2 | 3 | use super::{ 4 | structs::*, 5 | traits::*, 6 | }; 7 | use crate::internal::functional::{ 8 | base::*, 9 | type_app::*, 10 | }; 11 | 12 | pub fn extract_choice<'a, Row, F, T1, T2>(row: AppSum<'a, Row, F>) -> T2 13 | where 14 | F: TyCon, 15 | Row: FlattenSumApp<'a, F, FlattenApplied = T1>, 16 | T1: Into, 17 | { 18 | Row::flatten_sum(row).into() 19 | } 20 | 21 | pub fn get_sum<'a, Row, F>(row: AppSum<'a, Row, F>) -> Row::Applied 22 | where 23 | F: TyCon, 24 | Row: SumApp<'a, F>, 25 | { 26 | row.get_sum() 27 | } 28 | 29 | pub fn get_sum_borrow<'a, 'b, Row, F>( 30 | row: &'b AppSum<'a, Row, F> 31 | ) -> &'b Row::Applied 32 | where 33 | F: TyCon, 34 | Row: SumApp<'a, F>, 35 | { 36 | row.row.as_ref().get_sum_borrow() 37 | } 38 | 39 | #[allow(unreachable_code)] 40 | pub fn absurd(row1: AppSum<(), F>) -> A 41 | where 42 | F: TyCon, 43 | { 44 | match row1.get_sum() {} 45 | } 46 | 47 | // lift_sum : forall row f g 48 | // . (forall x . f x -> g x) 49 | // -> row f 50 | // -> row g 51 | pub fn lift_sum<'a, Row: 'a, F1: 'a, F2: 'a, Lift: 'a>( 52 | lift: Lift, 53 | sum: AppSum<'a, Row, F1>, 54 | ) -> AppSum<'a, Row, F2> 55 | where 56 | F1: TyCon, 57 | F2: TyCon, 58 | Row: SumFunctor, 59 | Lift: NaturalTransformation<'a, F1, F2>, 60 | { 61 | Row::lift_sum(lift, sum) 62 | } 63 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/type_app/impls.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | structs::*, 3 | traits::*, 4 | }; 5 | 6 | impl<'a, F, X, T> serde::Serialize for App<'a, F, X> 7 | where 8 | T: Send, 9 | F: TypeApp<'a, X, Applied = T>, 10 | T: serde::Serialize + for<'de> serde::Deserialize<'de>, 11 | { 12 | fn serialize( 13 | &self, 14 | serializer: S, 15 | ) -> Result 16 | where 17 | S: serde::Serializer, 18 | { 19 | self 20 | .applied 21 | .as_ref() 22 | .get_applied_borrow() 23 | .serialize(serializer) 24 | } 25 | } 26 | 27 | impl<'a, F, X, T: 'a> serde::Deserialize<'a> for App<'a, F, X> 28 | where 29 | F: TypeApp<'a, X, Applied = T>, 30 | T: serde::Serialize + for<'de> serde::Deserialize<'de>, 31 | { 32 | fn deserialize(deserializer: D) -> Result 33 | where 34 | D: serde::Deserializer<'a>, 35 | { 36 | let applied = T::deserialize(deserializer)?; 37 | 38 | Ok(App::new(applied)) 39 | } 40 | } 41 | 42 | impl<'a, T, F, A> HasTypeApp<'a, F, A> for T 43 | where 44 | T: Send, 45 | F: TypeApp<'a, A, Applied = T>, 46 | { 47 | fn get_applied(self: Box) -> Box 48 | { 49 | self 50 | } 51 | 52 | fn get_applied_borrow(&self) -> &F::Applied 53 | where 54 | F: TypeApp<'a, A>, 55 | { 56 | self 57 | } 58 | } 59 | 60 | impl TyCon for () {} 61 | 62 | impl<'a, A> TypeApp<'a, A> for () 63 | { 64 | type Applied = (); 65 | } 66 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/type_app/mod.rs: -------------------------------------------------------------------------------- 1 | mod impls; 2 | mod structs; 3 | mod traits; 4 | 5 | pub use impls::*; 6 | pub use structs::*; 7 | pub use traits::*; 8 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/type_app/structs.rs: -------------------------------------------------------------------------------- 1 | use super::traits::*; 2 | 3 | pub struct App<'a, F, A> 4 | { 5 | pub applied: Box + 'a>, 6 | } 7 | 8 | impl<'a, F, A> App<'a, F, A> 9 | { 10 | pub fn new(applied: F::Applied) -> App<'a, F, A> 11 | where 12 | F: TypeApp<'a, A>, 13 | F::Applied: 'a, 14 | { 15 | App { 16 | applied: Box::new(applied), 17 | } 18 | } 19 | 20 | pub fn get_applied(self) -> F::Applied 21 | where 22 | F: TypeApp<'a, A>, 23 | { 24 | *self.applied.get_applied() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/functional/type_app/traits.rs: -------------------------------------------------------------------------------- 1 | pub trait TyCon: Sized {} 2 | 3 | pub trait TypeApp<'a, A>: TyCon 4 | { 5 | type Applied: Sized + Send; 6 | } 7 | 8 | pub trait HasTypeApp<'a, F, A>: Send 9 | { 10 | fn get_applied(self: Box) -> Box 11 | where 12 | F: TypeApp<'a, A>; 13 | 14 | fn get_applied_borrow(&self) -> &F::Applied 15 | where 16 | F: TypeApp<'a, A>; 17 | } 18 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod base; 2 | pub mod functional; 3 | pub mod protocol; 4 | pub mod public; 5 | pub mod session; 6 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/channel/mod.rs: -------------------------------------------------------------------------------- 1 | mod receive; 2 | mod send; 3 | 4 | pub use receive::ReceiveChannel; 5 | pub use send::SendChannel; 6 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/channel/receive.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | marker::PhantomData, 4 | pin::Pin, 5 | }; 6 | 7 | use crate::internal::base::*; 8 | 9 | pub struct ReceiveChannel(PhantomData<(A, B)>); 10 | 11 | impl SealedProtocol for ReceiveChannel {} 12 | 13 | impl Protocol for ReceiveChannel 14 | where 15 | A: Protocol, 16 | B: Protocol, 17 | { 18 | type ClientEndpoint = (SenderOnce, B::ClientEndpoint); 19 | type ProviderEndpoint = 20 | (ReceiverOnce, B::ProviderEndpoint); 21 | 22 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 23 | { 24 | let (chan_sender, chan_receiver) = once_channel(); 25 | let (provider_end, client_end) = B::create_endpoints(); 26 | 27 | ((chan_receiver, provider_end), (chan_sender, client_end)) 28 | } 29 | 30 | fn forward( 31 | client_end: Self::ClientEndpoint, 32 | provider_end: Self::ProviderEndpoint, 33 | ) -> Pin + Send + 'static>> 34 | { 35 | let (chan_sender, client_end_b) = client_end; 36 | let (chan_receiver, provider_end_b) = provider_end; 37 | 38 | Box::pin(async { 39 | let chan = chan_receiver.recv().await.unwrap(); 40 | chan_sender.send(chan).unwrap(); 41 | 42 | B::forward(client_end_b, provider_end_b).await; 43 | }) 44 | } 45 | } 46 | 47 | impl RecApp for ReceiveChannel 48 | where 49 | P: RecApp, 50 | Q: RecApp, 51 | { 52 | type Applied = ReceiveChannel; 53 | } 54 | 55 | impl SharedRecApp for ReceiveChannel 56 | where 57 | B: SharedRecApp, 58 | { 59 | type Applied = ReceiveChannel; 60 | } 61 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/channel/send.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | marker::PhantomData, 4 | pin::Pin, 5 | }; 6 | 7 | use crate::internal::base::*; 8 | 9 | pub struct SendChannel(PhantomData<(A, B)>); 10 | 11 | impl SealedProtocol for SendChannel {} 12 | 13 | impl Protocol for SendChannel 14 | where 15 | A: Protocol, 16 | B: Protocol, 17 | { 18 | type ClientEndpoint = (ReceiverOnce, B::ClientEndpoint); 19 | type ProviderEndpoint = (SenderOnce, B::ProviderEndpoint); 20 | 21 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 22 | { 23 | let (chan_sender, chan_receiver) = once_channel(); 24 | let (provider_end, client_end) = B::create_endpoints(); 25 | 26 | ((chan_sender, provider_end), (chan_receiver, client_end)) 27 | } 28 | 29 | fn forward( 30 | client_end: Self::ClientEndpoint, 31 | provider_end: Self::ProviderEndpoint, 32 | ) -> Pin + Send + 'static>> 33 | { 34 | let (chan_receiver, client_end_b) = client_end; 35 | let (chan_sender, provider_end_b) = provider_end; 36 | 37 | Box::pin(async { 38 | let chan = chan_receiver.recv().await.unwrap(); 39 | chan_sender.send(chan).unwrap(); 40 | 41 | B::forward(client_end_b, provider_end_b).await; 42 | }) 43 | } 44 | } 45 | 46 | impl RecApp for SendChannel 47 | where 48 | P: RecApp, 49 | Q: RecApp, 50 | { 51 | type Applied = SendChannel; 52 | } 53 | 54 | impl SharedRecApp for SendChannel 55 | where 56 | P: Protocol, 57 | Q: SharedRecApp, 58 | { 59 | type Applied = SendChannel; 60 | } 61 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/choice/either.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use crate::internal::functional::{ 4 | nat::*, 5 | row::*, 6 | }; 7 | 8 | pub struct Either 9 | { 10 | phantom: PhantomData<(A, B)>, 11 | } 12 | 13 | impl ToRow for Either 14 | { 15 | type Row = (A, (B, ())); 16 | } 17 | 18 | pub type EitherRow = Sum>; 19 | 20 | #[allow(non_upper_case_globals)] 21 | pub const LeftLabel: ChoiceSelector = >::new(); 22 | 23 | #[allow(non_upper_case_globals)] 24 | pub const RightLabel: ChoiceSelector> = >>::new(); 25 | 26 | pub enum EitherChoice 27 | { 28 | Left(A), 29 | Right(B), 30 | } 31 | 32 | pub use EitherChoice::{ 33 | Left, 34 | Right, 35 | }; 36 | 37 | impl From>> for EitherChoice 38 | { 39 | fn from(row: Sum>) -> EitherChoice 40 | { 41 | match row { 42 | Sum::Inl(a) => Left(a), 43 | Sum::Inr(Sum::Inl(b)) => Right(b), 44 | Sum::Inr(Sum::Inr(bot)) => match bot {}, 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/choice/external_choice.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | marker::PhantomData, 4 | pin::Pin, 5 | }; 6 | 7 | use crate::internal::{ 8 | base::*, 9 | functional::*, 10 | }; 11 | 12 | pub struct ExternalChoice(PhantomData); 13 | 14 | impl SealedProtocol for ExternalChoice {} 15 | 16 | impl Protocol for ExternalChoice 17 | where 18 | Row: ToRow + Send + 'static, 19 | { 20 | type ClientEndpoint = 21 | SenderOnce>; 22 | type ProviderEndpoint = 23 | ReceiverOnce>; 24 | 25 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 26 | { 27 | let (sender, receiver) = once_channel(); 28 | 29 | (receiver, sender) 30 | } 31 | 32 | fn forward( 33 | client_end: Self::ClientEndpoint, 34 | provider_end: Self::ProviderEndpoint, 35 | ) -> Pin + Send + 'static>> 36 | { 37 | Box::pin(async { 38 | let payload = provider_end.recv().await.unwrap(); 39 | client_end.send(payload).unwrap(); 40 | }) 41 | } 42 | } 43 | 44 | impl RecApp for ExternalChoice 45 | where 46 | R: Send + 'static, 47 | Row2: RowCon, 48 | Row1: Send + 'static, 49 | Row1: ToRow, 50 | Row2: RecApp, 51 | Row3: RowCon, 52 | { 53 | type Applied = ExternalChoice>; 54 | } 55 | 56 | impl SharedRecApp for ExternalChoice 57 | where 58 | R: Send + 'static, 59 | Row2: RowCon, 60 | Row1: ToRow, 61 | Row2: SharedRecApp, 62 | Row3: RowCon, 63 | { 64 | type Applied = ExternalChoice>; 65 | } 66 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/choice/internal_choice.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | marker::PhantomData, 4 | pin::Pin, 5 | }; 6 | 7 | use crate::internal::{ 8 | base::*, 9 | functional::*, 10 | }; 11 | 12 | pub struct InternalChoice(PhantomData); 13 | 14 | impl SealedProtocol for InternalChoice {} 15 | 16 | impl Protocol for InternalChoice 17 | where 18 | Row: ToRow + Send + 'static, 19 | { 20 | type ClientEndpoint = 21 | ReceiverOnce>; 22 | type ProviderEndpoint = 23 | SenderOnce>; 24 | 25 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 26 | { 27 | once_channel() 28 | } 29 | 30 | fn forward( 31 | client_end: Self::ClientEndpoint, 32 | provider_end: Self::ProviderEndpoint, 33 | ) -> Pin + Send + 'static>> 34 | { 35 | Box::pin(async { 36 | let endpoint = client_end.recv().await.unwrap(); 37 | provider_end.send(endpoint).unwrap(); 38 | }) 39 | } 40 | } 41 | 42 | impl RecApp for InternalChoice 43 | where 44 | A: Send + 'static, 45 | Row1: Send + 'static, 46 | Row1: ToRow, 47 | Row2: RowCon, 48 | Row2: RecApp, 49 | Row3: RowCon, 50 | { 51 | type Applied = InternalChoice>; 52 | } 53 | 54 | impl SharedRecApp for InternalChoice 55 | where 56 | A: Send + 'static, 57 | Row1: ToRow, 58 | Row2: RowCon, 59 | Row2: SharedRecApp, 60 | Row3: RowCon, 61 | { 62 | type Applied = InternalChoice>; 63 | } 64 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/choice/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod either; 2 | 3 | mod external_choice; 4 | mod internal_choice; 5 | 6 | pub use external_choice::ExternalChoice; 7 | pub use internal_choice::InternalChoice; 8 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/end.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | 6 | use crate::internal::base::*; 7 | 8 | pub struct End; 9 | 10 | impl SealedProtocol for End {} 11 | 12 | impl Protocol for End 13 | { 14 | type ClientEndpoint = ReceiverOnce<()>; 15 | type ProviderEndpoint = SenderOnce<()>; 16 | 17 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 18 | { 19 | once_channel() 20 | } 21 | 22 | fn forward( 23 | client_end: Self::ClientEndpoint, 24 | provider_end: Self::ProviderEndpoint, 25 | ) -> Pin + Send + 'static>> 26 | { 27 | Box::pin(async { 28 | let payload = client_end.recv().await.unwrap(); 29 | provider_end.send(payload).unwrap(); 30 | }) 31 | } 32 | } 33 | 34 | impl RecApp for End 35 | { 36 | type Applied = End; 37 | } 38 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod public; 2 | 3 | mod channel; 4 | mod choice; 5 | mod end; 6 | 7 | mod shared; 8 | mod value; 9 | mod wrap; 10 | 11 | #[doc(inline)] 12 | pub use self::{ 13 | channel::{ 14 | ReceiveChannel, 15 | SendChannel, 16 | }, 17 | choice::{ 18 | either, 19 | ExternalChoice, 20 | InternalChoice, 21 | }, 22 | end::End, 23 | shared::{ 24 | LinearToShared, 25 | Lock, 26 | SharedToLinear, 27 | }, 28 | value::{ 29 | ReceiveValue, 30 | SendValue, 31 | }, 32 | wrap::{ 33 | Wrap, 34 | Wrapper, 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/public.rs: -------------------------------------------------------------------------------- 1 | #[doc(inline)] 2 | pub use super::{ 3 | End, 4 | ExternalChoice, 5 | InternalChoice, 6 | LinearToShared, 7 | ReceiveChannel, 8 | ReceiveValue, 9 | SendChannel, 10 | SendValue, 11 | SharedToLinear, 12 | Wrap, 13 | Wrapper, 14 | }; 15 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/shared/linear_to_shared.rs: -------------------------------------------------------------------------------- 1 | use super::shared_to_linear::SharedToLinear; 2 | use crate::internal::base::*; 3 | 4 | pub trait HasSharedRecApp: Send + 'static 5 | { 6 | fn get_applied(self: Box) -> ::ClientEndpoint 7 | where 8 | F: SharedRecApp, 9 | F::Applied: Protocol; 10 | } 11 | 12 | impl HasSharedRecApp for E 13 | where 14 | F: 'static, 15 | A: 'static, 16 | E: Send + 'static, 17 | FA: Protocol, 18 | F: SharedRecApp, 19 | { 20 | fn get_applied(self: Box) -> ::ClientEndpoint 21 | { 22 | *self 23 | } 24 | } 25 | 26 | pub struct LinearToShared 27 | { 28 | pub(crate) linear: 29 | Box>>>, 30 | } 31 | 32 | impl SealedSharedProtocol for LinearToShared {} 33 | 34 | impl SharedProtocol for LinearToShared 35 | where 36 | F: Protocol, 37 | F: SharedRecApp>>, 38 | F::Applied: Protocol, 39 | { 40 | } 41 | 42 | impl ForwardChannel for LinearToShared 43 | where 44 | F: SharedRecApp>, Applied = T>, 45 | F: Send + 'static, 46 | T: Protocol, 47 | E: ForwardChannel, 48 | { 49 | fn forward_to( 50 | self, 51 | sender: OpaqueSender, 52 | receiver: OpaqueReceiver, 53 | ) 54 | { 55 | self.linear.get_applied().forward_to(sender, receiver) 56 | } 57 | 58 | fn forward_from( 59 | sender: OpaqueSender, 60 | receiver: OpaqueReceiver, 61 | ) -> Self 62 | { 63 | LinearToShared { 64 | linear: Box::new(E::forward_from(sender, receiver)), 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/shared/lock.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | 6 | use super::{ 7 | linear_to_shared::LinearToShared, 8 | shared_to_linear::SharedToLinear, 9 | }; 10 | use crate::internal::base::*; 11 | 12 | pub struct Lock 13 | where 14 | F: SharedRecApp>>, 15 | { 16 | pub(crate) unlock: Receiver<(SenderOnce<()>, SenderOnce>)>, 17 | } 18 | 19 | impl SealedProtocol for Lock where 20 | F: SharedRecApp>> 21 | { 22 | } 23 | 24 | impl Protocol for Lock 25 | where 26 | F: Protocol, 27 | F: SharedRecApp>>, 28 | F::Applied: Protocol, 29 | { 30 | type ClientEndpoint = ReceiverOnce>; 31 | type ProviderEndpoint = SenderOnce>; 32 | 33 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 34 | { 35 | once_channel() 36 | } 37 | 38 | fn forward( 39 | client_end: Self::ClientEndpoint, 40 | provider_end: Self::ProviderEndpoint, 41 | ) -> Pin + Send + 'static>> 42 | { 43 | Box::pin(async { 44 | let payload = client_end.recv().await.unwrap(); 45 | provider_end.send(payload).unwrap(); 46 | }) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/shared/mod.rs: -------------------------------------------------------------------------------- 1 | mod linear_to_shared; 2 | mod lock; 3 | mod shared_to_linear; 4 | 5 | pub use linear_to_shared::LinearToShared; 6 | pub use lock::Lock; 7 | pub use shared_to_linear::SharedToLinear; 8 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/shared/shared_to_linear.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | use std::marker::PhantomData; 6 | 7 | use super::linear_to_shared::LinearToShared; 8 | use crate::internal::base::*; 9 | 10 | pub struct SharedToLinear(PhantomData); 11 | 12 | impl SealedProtocol for SharedToLinear> {} 13 | 14 | impl Protocol for SharedToLinear> 15 | where 16 | F: Send + 'static, 17 | F: SharedRecApp>>, 18 | { 19 | type ClientEndpoint = SenderOnce<()>; 20 | type ProviderEndpoint = ReceiverOnce<()>; 21 | 22 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 23 | { 24 | let (sender, receiver) = once_channel(); 25 | (receiver, sender) 26 | } 27 | 28 | fn forward( 29 | client_end: Self::ClientEndpoint, 30 | provider_end: Self::ProviderEndpoint, 31 | ) -> Pin + Send + 'static>> 32 | { 33 | Box::pin(async { 34 | let payload = provider_end.recv().await.unwrap(); 35 | client_end.send(payload).unwrap(); 36 | }) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/value/mod.rs: -------------------------------------------------------------------------------- 1 | mod receive; 2 | mod send; 3 | 4 | pub use receive::ReceiveValue; 5 | pub use send::SendValue; 6 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/value/receive.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | marker::PhantomData, 4 | pin::Pin, 5 | }; 6 | 7 | use crate::internal::base::*; 8 | 9 | pub struct ReceiveValue(PhantomData<(T, A)>); 10 | 11 | impl SealedProtocol for ReceiveValue {} 12 | 13 | impl Protocol for ReceiveValue 14 | where 15 | T: Send + 'static, 16 | A: Protocol, 17 | { 18 | type ClientEndpoint = SenderOnce<(Value, A::ProviderEndpoint)>; 19 | type ProviderEndpoint = ReceiverOnce<(Value, A::ProviderEndpoint)>; 20 | 21 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 22 | { 23 | let (sender, receiver) = once_channel(); 24 | (receiver, sender) 25 | } 26 | 27 | fn forward( 28 | client_end: Self::ClientEndpoint, 29 | provider_end: Self::ProviderEndpoint, 30 | ) -> Pin + Send + 'static>> 31 | { 32 | Box::pin(async { 33 | let payload = provider_end.recv().await.unwrap(); 34 | client_end.send(payload).unwrap(); 35 | }) 36 | } 37 | } 38 | 39 | impl RecApp for ReceiveValue 40 | where 41 | X: Send + 'static, 42 | T: Send + 'static, 43 | A: RecApp, 44 | { 45 | type Applied = ReceiveValue; 46 | } 47 | 48 | impl SharedRecApp for ReceiveValue 49 | where 50 | T: Send + 'static, 51 | A: SharedRecApp, 52 | { 53 | type Applied = ReceiveValue; 54 | } 55 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/value/send.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | marker::PhantomData, 4 | pin::Pin, 5 | }; 6 | 7 | use crate::internal::base::*; 8 | 9 | pub struct SendValue(PhantomData<(T, A)>); 10 | 11 | impl SealedProtocol for SendValue {} 12 | 13 | impl Protocol for SendValue 14 | where 15 | T: Send + 'static, 16 | A: Protocol, 17 | { 18 | type ClientEndpoint = ReceiverOnce<(Value, A::ClientEndpoint)>; 19 | type ProviderEndpoint = SenderOnce<(Value, A::ClientEndpoint)>; 20 | 21 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 22 | { 23 | once_channel() 24 | } 25 | 26 | fn forward( 27 | client_end: Self::ClientEndpoint, 28 | provider_end: Self::ProviderEndpoint, 29 | ) -> Pin + Send + 'static>> 30 | { 31 | Box::pin(async { 32 | let payload = client_end.recv().await.unwrap(); 33 | provider_end.send(payload).unwrap(); 34 | }) 35 | } 36 | } 37 | 38 | impl RecApp for SendValue 39 | where 40 | T: Send + 'static, 41 | A: RecApp, 42 | { 43 | type Applied = SendValue; 44 | } 45 | 46 | impl SharedRecApp for SendValue 47 | where 48 | T: Send + 'static, 49 | A: SharedRecApp, 50 | { 51 | type Applied = SendValue; 52 | } 53 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/protocol/wrap.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | pin::Pin, 4 | }; 5 | 6 | use crate::internal::base::*; 7 | 8 | pub trait Wrapper 9 | { 10 | type Unwrap: Protocol; 11 | } 12 | 13 | pub struct Wrap 14 | where 15 | T: Wrapper, 16 | { 17 | pub(crate) unwrap: Box>, 18 | } 19 | 20 | pub trait HasWrapped: Send + 'static 21 | { 22 | fn unwrap(self: Box) -> ::ClientEndpoint 23 | where 24 | T: Wrapper, 25 | T::Unwrap: Protocol; 26 | } 27 | 28 | impl HasWrapped for W::ClientEndpoint 29 | where 30 | T: Wrapper, 31 | W: Protocol, 32 | { 33 | fn unwrap(self: Box) -> ::ClientEndpoint 34 | { 35 | *self 36 | } 37 | } 38 | 39 | impl SealedProtocol for Wrap where T: Wrapper {} 40 | 41 | impl Protocol for Wrap 42 | where 43 | T: Wrapper, 44 | T: Send + 'static, 45 | { 46 | type ClientEndpoint = ReceiverOnce>; 47 | type ProviderEndpoint = SenderOnce>; 48 | 49 | fn create_endpoints() -> (Self::ProviderEndpoint, Self::ClientEndpoint) 50 | { 51 | once_channel() 52 | } 53 | 54 | fn forward( 55 | client_end: Self::ClientEndpoint, 56 | provider_end: Self::ProviderEndpoint, 57 | ) -> Pin + Send + 'static>> 58 | { 59 | Box::pin(async { 60 | let payload = client_end.recv().await.unwrap(); 61 | provider_end.send(payload).unwrap(); 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/public.rs: -------------------------------------------------------------------------------- 1 | pub mod prelude 2 | { 3 | #[doc(inline)] 4 | pub use crate::internal::{ 5 | base::public::{ 6 | AppendContext, 7 | Context, 8 | ContextLens, 9 | Empty, 10 | EmptyContext, 11 | ForwardChannel, 12 | HasRecApp, 13 | PartialSession, 14 | Protocol, 15 | Rec, 16 | RecApp, 17 | RecX, 18 | Release, 19 | Session, 20 | SharedChannel, 21 | SharedProtocol, 22 | SharedRecApp, 23 | SharedSession, 24 | Slot, 25 | }, 26 | functional::public::{ 27 | absurd, 28 | extract_choice, 29 | get_sum, 30 | get_sum_borrow, 31 | lift_sum, 32 | succ, 33 | App, 34 | AppSum, 35 | Bottom, 36 | ChoiceSelector, 37 | FlattenSumApp, 38 | HasSumApp, 39 | HasTypeApp, 40 | Nat, 41 | NaturalTransformation, 42 | Prism, 43 | RowCon, 44 | Sum, 45 | SumApp, 46 | SumFunctor, 47 | ToRow, 48 | TyCon, 49 | TypeApp, 50 | S, 51 | Z, 52 | }, 53 | protocol::public::{ 54 | End, 55 | ExternalChoice, 56 | InternalChoice, 57 | LinearToShared, 58 | ReceiveChannel, 59 | ReceiveValue, 60 | SendChannel, 61 | SendValue, 62 | SharedToLinear, 63 | Wrap, 64 | Wrapper, 65 | }, 66 | session::public::{ 67 | accept_shared_session, 68 | acquire_shared_session, 69 | append_emtpy_slot, 70 | apply_channel, 71 | async_acquire_shared_session, 72 | async_acquire_shared_session_with_result, 73 | case, 74 | choose, 75 | cut, 76 | cut_append, 77 | detach_shared_session, 78 | fix_session, 79 | fork, 80 | forward, 81 | include_session, 82 | join_sessions, 83 | new_session, 84 | offer_case, 85 | offer_choice, 86 | partial_session, 87 | partial_session_1, 88 | partial_session_2, 89 | receive_channel, 90 | receive_channel_from, 91 | receive_value, 92 | receive_value_from, 93 | release_shared_session, 94 | run_cont, 95 | run_session, 96 | run_session_with_result, 97 | run_shared_session, 98 | run_shared_session_with_join_handle, 99 | send_channel_from, 100 | send_channel_to, 101 | send_channel_to_session, 102 | send_value, 103 | send_value_to, 104 | session, 105 | session_1, 106 | session_2, 107 | shared_forward, 108 | step, 109 | terminate, 110 | terminate_async, 111 | terminate_nil, 112 | unfix_session, 113 | unwrap_session, 114 | wait, 115 | wait_session, 116 | wait_sessions, 117 | wrap_session, 118 | AllLeft, 119 | AllRight, 120 | Cut, 121 | L, 122 | R, 123 | }, 124 | }; 125 | // Export macros 126 | #[doc(inline)] 127 | pub use crate::{ 128 | acquire_shared_session, 129 | case, 130 | choose, 131 | cut, 132 | define_choice, 133 | include_session, 134 | offer_case, 135 | offer_choice, 136 | receive_channel, 137 | receive_channel_from, 138 | receive_channels, 139 | receive_value, 140 | receive_value_from, 141 | send_value, 142 | send_value_to, 143 | terminate, 144 | wait, 145 | wait_all, 146 | HList, 147 | Sum, 148 | }; 149 | } 150 | 151 | #[doc(inline)] 152 | pub use crate::internal::{ 153 | base::public as base, 154 | functional::public as functional, 155 | protocol::either, 156 | protocol::public as protocol, 157 | session::public as session, 158 | }; 159 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/apply.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::{ 2 | base::{ 3 | AppendContext, 4 | Context, 5 | ContextLens, 6 | Empty, 7 | PartialSession, 8 | Protocol, 9 | Session, 10 | }, 11 | protocol::{ 12 | End, 13 | ReceiveChannel, 14 | }, 15 | session::{ 16 | channel::send_channel_to, 17 | end::wait, 18 | forward::forward, 19 | include::include_session, 20 | }, 21 | }; 22 | 23 | pub fn apply_channel( 24 | f: Session>, 25 | a: Session, 26 | ) -> Session 27 | where 28 | A: Protocol, 29 | B: Protocol, 30 | { 31 | include_session(f, move |c1| { 32 | include_session(a, move |c2| send_channel_to(c1, c2, forward(c1))) 33 | }) 34 | } 35 | 36 | pub fn send_channel_to_session( 37 | n: N, 38 | session: Session>, 39 | cont: PartialSession, 40 | ) -> PartialSession 41 | where 42 | C1: Context, 43 | C2: Context, 44 | C3: Context, 45 | C4: Context, 46 | C5: Context, 47 | A: Protocol, 48 | B: Protocol, 49 | C1: AppendContext<(ReceiveChannel, ()), Appended = C2>, 50 | C1::Length: ContextLens, End, Target = C4>, 51 | C1::Length: ContextLens, 52 | N: ContextLens, 53 | { 54 | include_session(session, |chan| send_channel_to(chan, n, wait(chan, cont))) 55 | } 56 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/channel/mod.rs: -------------------------------------------------------------------------------- 1 | mod receive; 2 | mod send; 3 | 4 | pub use receive::{ 5 | receive_channel, 6 | send_channel_to, 7 | }; 8 | pub use send::{ 9 | fork, 10 | receive_channel_from, 11 | send_channel_from, 12 | }; 13 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/channel/receive.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::{ 2 | base::{ 3 | unsafe_create_session, 4 | unsafe_run_session, 5 | AppendContext, 6 | Context, 7 | ContextLens, 8 | Empty, 9 | PartialSession, 10 | Protocol, 11 | }, 12 | functional::{ 13 | App, 14 | Nat, 15 | }, 16 | protocol::ReceiveChannel, 17 | }; 18 | 19 | pub fn receive_channel( 20 | cont: impl FnOnce(N) -> PartialSession 21 | ) -> PartialSession> 22 | where 23 | N: Nat, 24 | A: Protocol, 25 | B: Protocol, 26 | C1: Context, 27 | C2: Context, 28 | C1: AppendContext<(A, ()), Appended = C2>, 29 | { 30 | let cont2 = cont(N::nat()); 31 | 32 | unsafe_create_session::, _, _>( 33 | move |ctx1, (chan_receiver, provider_end)| async move { 34 | let client_end = chan_receiver.recv().await.unwrap(); 35 | 36 | let ctx2 = C1::append_context(ctx1, (App::new(client_end), ())); 37 | 38 | unsafe_run_session(cont2, ctx2, provider_end).await; 39 | }, 40 | ) 41 | } 42 | 43 | pub fn send_channel_to( 44 | _n: N, 45 | _m: M, 46 | cont: PartialSession, 47 | ) -> PartialSession 48 | where 49 | C1: Context, 50 | C2: Context, 51 | C3: Context, 52 | A1: Protocol, 53 | A2: Protocol, 54 | B: Protocol, 55 | N: ContextLens, A2, Target = C3>, 56 | M: ContextLens, 57 | { 58 | unsafe_create_session(move |ctx1, provider_end_b| async move { 59 | let (client_end_1, ctx2) = M::extract_source(ctx1); 60 | 61 | let ctx3 = M::insert_target((), ctx2); 62 | 63 | let (endpoint, ctx4) = N::extract_source(ctx3); 64 | 65 | let (chan_sender, client_end_2) = endpoint.get_applied(); 66 | 67 | chan_sender.send(client_end_1.get_applied()).unwrap(); 68 | 69 | let ctx5 = N::insert_target(App::new(client_end_2), ctx4); 70 | 71 | unsafe_run_session(cont, ctx5, provider_end_b).await; 72 | }) 73 | } 74 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/channel/send.rs: -------------------------------------------------------------------------------- 1 | use tokio::{ 2 | task, 3 | try_join, 4 | }; 5 | 6 | use crate::internal::{ 7 | base::{ 8 | unsafe_create_session, 9 | unsafe_run_session, 10 | AppendContext, 11 | Context, 12 | ContextLens, 13 | Empty, 14 | PartialSession, 15 | Protocol, 16 | }, 17 | functional::{ 18 | App, 19 | Nat, 20 | }, 21 | protocol::SendChannel, 22 | }; 23 | 24 | pub fn send_channel_from( 25 | _n: N, 26 | cont: PartialSession, 27 | ) -> PartialSession> 28 | where 29 | A: Protocol, 30 | B: Protocol, 31 | C1: Context, 32 | C2: Context, 33 | N: ContextLens, 34 | { 35 | unsafe_create_session::, _, _>( 36 | move |ctx1, (chan_sender, provider_end)| async move { 37 | let (endpoint, ctx2) = N::extract_source(ctx1); 38 | 39 | let client_end = endpoint.get_applied(); 40 | 41 | let ctx3 = N::insert_target((), ctx2); 42 | 43 | chan_sender.send(client_end).unwrap(); 44 | 45 | unsafe_run_session(cont, ctx3, provider_end).await; 46 | }, 47 | ) 48 | } 49 | 50 | pub fn receive_channel_from( 51 | _n: N, 52 | cont1: impl FnOnce(M) -> PartialSession, 53 | ) -> PartialSession 54 | where 55 | A1: Protocol, 56 | A2: Protocol, 57 | B: Protocol, 58 | C1: Context, 59 | C2: AppendContext<(A1, ()), Appended = C3>, 60 | C3: Context, 61 | N: ContextLens, A2, Target = C2>, 62 | M: Nat, 63 | { 64 | let cont2 = cont1(M::nat()); 65 | 66 | unsafe_create_session(move |ctx1, provider_end| async move { 67 | let (endpoint, ctx2) = N::extract_source(ctx1); 68 | 69 | let (chan_receiver, client_end2) = endpoint.get_applied(); 70 | 71 | let client_end1 = chan_receiver.recv().await.unwrap(); 72 | 73 | let ctx3 = N::insert_target(App::new(client_end2), ctx2); 74 | 75 | let ctx4 = >::append_context( 76 | ctx3, 77 | (App::new(client_end1), ()), 78 | ); 79 | 80 | unsafe_run_session(cont2, ctx4, provider_end).await; 81 | }) 82 | } 83 | 84 | /* 85 | Multiplicative Conjunction, Alternative Parallel Version 86 | 87 | 88 | cont1 :: Δ ⊢ P cont2 :: Δ' ⊢ Q 89 | ======================================== 90 | fork(cont1, cont2) :: Δ, Δ' ⊢ P ⊗ Q 91 | 92 | Takes in two session builders and return a new session builder 93 | with its inputs combined and outputs a parallel context 94 | */ 95 | 96 | pub fn fork( 97 | cont1: PartialSession, 98 | cont2: PartialSession, 99 | ) -> PartialSession> 100 | where 101 | A: Protocol, 102 | B: Protocol, 103 | C1: Context, 104 | C2: Context, 105 | C1: AppendContext, 106 | { 107 | unsafe_create_session::, _, _>( 108 | move |ctx, (chan_sender, provider_end_b)| async move { 109 | let (ctx1, ctx2) = C1::split_context(ctx); 110 | 111 | let (provider_end_a, client_end_a) = A::create_endpoints(); 112 | 113 | let child1 = task::spawn(async move { 114 | unsafe_run_session(cont1, ctx1, provider_end_a).await; 115 | }); 116 | 117 | chan_sender.send(client_end_a).unwrap(); 118 | 119 | let child2 = task::spawn(async move { 120 | unsafe_run_session(cont2, ctx2, provider_end_b).await; 121 | }); 122 | 123 | try_join!(child1, child2).unwrap(); 124 | }, 125 | ) 126 | } 127 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/choice/external/choose.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::{ 2 | base::{ 3 | unsafe_create_session, 4 | unsafe_run_session, 5 | Context, 6 | ContextLens, 7 | PartialSession, 8 | Protocol, 9 | }, 10 | functional::{ 11 | App, 12 | Prism, 13 | RowCon, 14 | ToRow, 15 | }, 16 | protocol::ExternalChoice, 17 | }; 18 | 19 | pub fn choose( 20 | _: N, 21 | _: M, 22 | cont: PartialSession, 23 | ) -> PartialSession 24 | where 25 | C1: Context, 26 | C2: Context, 27 | A: Protocol, 28 | B: Protocol, 29 | Row2: RowCon, 30 | Row1: Send + 'static, 31 | Row2: Send + 'static, 32 | Row1: ToRow, 33 | N: ContextLens, B, Target = C2>, 34 | M: Prism, 35 | { 36 | unsafe_create_session(move |ctx1, provider_end| async move { 37 | let (endpoint, ctx2) = N::extract_source(ctx1); 38 | 39 | let choice_sender = endpoint.get_applied(); 40 | 41 | let (provider_end_b, client_end_b) = B::create_endpoints(); 42 | 43 | let provider_end_sum = M::inject_elem(App::new(provider_end_b)); 44 | 45 | choice_sender.send(provider_end_sum).unwrap(); 46 | 47 | let ctx3 = N::insert_target(App::new(client_end_b), ctx2); 48 | 49 | unsafe_run_session(cont, ctx3, provider_end).await; 50 | }) 51 | } 52 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/choice/external/mod.rs: -------------------------------------------------------------------------------- 1 | mod choose; 2 | pub mod offer_choice; 3 | 4 | pub use choose::choose; 5 | pub use offer_choice::offer_choice; 6 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/choice/external/offer_choice.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | marker::PhantomData, 4 | pin::Pin, 5 | }; 6 | 7 | use tokio::task; 8 | 9 | use crate::internal::{ 10 | base::{ 11 | unsafe_create_session, 12 | unsafe_run_session, 13 | Context, 14 | PartialSession, 15 | Protocol, 16 | ProviderEndpointF, 17 | }, 18 | functional::{ 19 | App, 20 | AppSum, 21 | NaturalTransformation, 22 | RowCon, 23 | SumFunctor, 24 | ToRow, 25 | TyCon, 26 | TypeApp, 27 | }, 28 | protocol::ExternalChoice, 29 | session::choice::run_cont::RunCont, 30 | }; 31 | 32 | pub fn offer_choice( 33 | cont1: impl for<'r> FnOnce( 34 | AppSum<'r, Row2, InjectSessionF<'r, Row1, C>>, 35 | ) -> ContSum<'r, Row1, C> 36 | + Send 37 | + 'static 38 | ) -> PartialSession> 39 | where 40 | C: Context, 41 | Row1: Send + 'static, 42 | Row2: Send + 'static, 43 | Row1: ToRow, 44 | Row2: RowCon, 45 | Row2: SumFunctor, 46 | { 47 | unsafe_create_session::, _, _>( 48 | move |ctx, choice_receiver| async move { 49 | let provider_end_sum = choice_receiver.recv().await.unwrap(); 50 | 51 | let cont_sum_1 = 52 | provider_end_sum_to_cont_sum::(ctx, provider_end_sum); 53 | 54 | let res = cont1(cont_sum_1); 55 | 56 | task::spawn(async move { 57 | res.future.await; 58 | }); 59 | }, 60 | ) 61 | } 62 | 63 | pub struct InjectSession<'r, Row, C: Context, A> 64 | { 65 | ctx: C::Endpoints, 66 | provider_end: App<'r, ProviderEndpointF, A>, 67 | phantom: PhantomData<(Box>, Row)>, 68 | } 69 | 70 | pub struct InjectSessionF<'r, Row, C>(PhantomData<&'r (Row, C)>); 71 | 72 | pub struct ContSum<'r, Row, C> 73 | { 74 | future: Pin + Send + 'r>>, 75 | phantom: PhantomData<(Box>, C, Row)>, 76 | } 77 | 78 | impl<'r, Row: 'r, C: Context, A: Protocol> RunCont 79 | for InjectSession<'r, Row, C, A> 80 | where 81 | Row: Send, 82 | { 83 | type Ret = ContSum<'r, Row, C>; 84 | 85 | fn run_cont( 86 | self, 87 | session: PartialSession, 88 | ) -> Self::Ret 89 | { 90 | ContSum { 91 | future: Box::pin(async move { 92 | unsafe_run_session(session, self.ctx, self.provider_end.get_applied()) 93 | .await; 94 | }), 95 | phantom: PhantomData, 96 | } 97 | } 98 | } 99 | 100 | pub trait Invariant<'r>: Send {} 101 | 102 | impl<'r, Row, C: 'static> TyCon for InjectSessionF<'r, Row, C> {} 103 | 104 | impl<'r, 'a, Row, C: Context, A: 'r> TypeApp<'a, A> 105 | for InjectSessionF<'r, Row, C> 106 | where 107 | Row: Send, 108 | { 109 | type Applied = InjectSession<'r, Row, C, A>; 110 | } 111 | 112 | fn provider_end_sum_to_cont_sum( 113 | ctx: C::Endpoints, 114 | provider_end_sum: AppSum<'static, Row2, ProviderEndpointF>, 115 | ) -> AppSum> 116 | where 117 | Row1: Send, 118 | Row2: SumFunctor, 119 | C: Context, 120 | { 121 | struct ProviderEndToCont 122 | { 123 | ctx: C::Endpoints, 124 | } 125 | 126 | impl<'r, Row: Send, C: Context> 127 | NaturalTransformation<'r, ProviderEndpointF, InjectSessionF<'r, Row, C>> 128 | for ProviderEndToCont 129 | { 130 | fn lift( 131 | self, 132 | provider_end: App<'r, ProviderEndpointF, A>, 133 | ) -> App<'r, InjectSessionF<'r, Row, C>, A> 134 | { 135 | App::new(InjectSession { 136 | ctx: self.ctx, 137 | provider_end, 138 | phantom: PhantomData, 139 | }) 140 | } 141 | } 142 | 143 | Row2::lift_sum(ProviderEndToCont { ctx }, provider_end_sum) 144 | } 145 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/choice/internal/case.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | future::Future, 3 | marker::PhantomData, 4 | pin::Pin, 5 | }; 6 | 7 | use crate::internal::{ 8 | base::{ 9 | unsafe_create_session, 10 | unsafe_run_session, 11 | ClientEndpointF, 12 | Context, 13 | ContextLens, 14 | Empty, 15 | PartialSession, 16 | Protocol, 17 | ProviderEndpointF, 18 | }, 19 | functional::{ 20 | App, 21 | AppSum, 22 | NaturalTransformation, 23 | SumFunctor, 24 | ToRow, 25 | TyCon, 26 | TypeApp, 27 | }, 28 | protocol::InternalChoice, 29 | session::choice::run_cont::RunCont, 30 | }; 31 | 32 | pub fn case( 33 | _: N, 34 | cont1: impl for<'r> FnOnce( 35 | AppSum<'r, Row2, ContF<'r, N, C2, B>>, 36 | ) -> ChoiceRet<'r, N, C2, B> 37 | + Send 38 | + 'static, 39 | ) -> PartialSession 40 | where 41 | B: Protocol, 42 | C1: Context, 43 | C2: Context, 44 | Row1: Send + 'static, 45 | Row2: Send + 'static, 46 | Row1: ToRow, 47 | N: ContextLens, Empty, Target = C2>, 48 | Row2: SumFunctor, 49 | { 50 | unsafe_create_session::(move |ctx1, provider_end| async move { 51 | let (endpoint, ctx2) = N::extract_source(ctx1); 52 | 53 | let ctx3 = N::insert_target((), ctx2); 54 | 55 | let client_end_sum_receiver = endpoint.get_applied(); 56 | 57 | let client_end_sum = client_end_sum_receiver.recv().await.unwrap(); 58 | 59 | let cont_sum = client_end_sum_to_cont_sum::( 60 | ctx3, 61 | App::new(provider_end), 62 | client_end_sum, 63 | ); 64 | 65 | let res = cont1(cont_sum); 66 | res.future.await; 67 | }) 68 | } 69 | 70 | pub struct ContF<'r, N, C, B>(PhantomData<&'r (N, C, B)>); 71 | 72 | pub trait Invariant<'r>: Send {} 73 | 74 | pub struct ChoiceCont<'r, N, C, B, A> 75 | where 76 | C: Context, 77 | { 78 | ctx: C::Endpoints, 79 | provider_end: App<'static, ProviderEndpointF, B>, 80 | client_end: App<'r, ClientEndpointF, A>, 81 | phantom: PhantomData<(Box>, N, C)>, 82 | } 83 | 84 | impl<'r, N, C, B> TyCon for ContF<'r, N, C, B> {} 85 | 86 | impl<'r, 'a, N, C, B, A: 'r> TypeApp<'a, A> for ContF<'r, N, C, B> 87 | where 88 | C: Context, 89 | N: Send, 90 | { 91 | type Applied = ChoiceCont<'r, N, C, B, A>; 92 | } 93 | 94 | pub struct ChoiceRet<'r, N, C, B> 95 | { 96 | future: Pin + Send + 'r>>, 97 | phantom: PhantomData<(Box>, N, C, B)>, 98 | } 99 | 100 | impl<'r, N, C1, C2, B, A> RunCont for ChoiceCont<'r, N, C1, B, A> 101 | where 102 | A: Protocol, 103 | B: Protocol, 104 | C1: Context, 105 | C2: Context, 106 | N: ContextLens, 107 | { 108 | type Ret = ChoiceRet<'r, N, C1, B>; 109 | 110 | fn run_cont( 111 | self, 112 | session: PartialSession, 113 | ) -> Self::Ret 114 | { 115 | ChoiceRet { 116 | future: Box::pin(async move { 117 | let ((), ctx1) = N::extract_source(self.ctx); 118 | let client_end = self.client_end.get_applied(); 119 | 120 | let ctx2 = N::insert_target(App::new(client_end), ctx1); 121 | unsafe_run_session(session, ctx2, self.provider_end.get_applied()) 122 | .await; 123 | }), 124 | phantom: PhantomData, 125 | } 126 | } 127 | } 128 | 129 | fn client_end_sum_to_cont_sum( 130 | ctx: C::Endpoints, 131 | provider_end: App<'static, ProviderEndpointF, B>, 132 | client_end_sum: AppSum<'static, Row, ClientEndpointF>, 133 | ) -> AppSum<'static, Row, ContF<'static, N, C, B>> 134 | where 135 | C: Context, 136 | N: Send, 137 | Row: SumFunctor + Send + 'static, 138 | { 139 | struct Trans 140 | { 141 | ctx: C::Endpoints, 142 | provider_end: App<'static, ProviderEndpointF, B>, 143 | } 144 | 145 | impl<'r, N, C, B> 146 | NaturalTransformation<'r, ClientEndpointF, ContF<'r, N, C, B>> 147 | for Trans 148 | where 149 | C: Context, 150 | N: Send, 151 | { 152 | fn lift( 153 | self, 154 | client_end: App<'r, ClientEndpointF, A>, 155 | ) -> App<'r, ContF<'r, N, C, B>, A> 156 | { 157 | App::new(ChoiceCont { 158 | ctx: self.ctx, 159 | provider_end: self.provider_end, 160 | client_end, 161 | phantom: PhantomData, 162 | }) 163 | } 164 | } 165 | 166 | Row::lift_sum(Trans { ctx, provider_end }, client_end_sum) 167 | } 168 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/choice/internal/mod.rs: -------------------------------------------------------------------------------- 1 | mod case; 2 | mod offer_case; 3 | 4 | pub use case::case; 5 | pub use offer_case::offer_case; 6 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/choice/internal/offer_case.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::{ 2 | base::{ 3 | unsafe_create_session, 4 | unsafe_run_session, 5 | Context, 6 | PartialSession, 7 | Protocol, 8 | }, 9 | functional::{ 10 | App, 11 | Prism, 12 | RowCon, 13 | ToRow, 14 | }, 15 | protocol::InternalChoice, 16 | }; 17 | 18 | pub fn offer_case( 19 | _: N, 20 | cont: PartialSession, 21 | ) -> PartialSession> 22 | where 23 | C: Context, 24 | A: Protocol, 25 | Row1: Send + 'static, 26 | Row2: Send + 'static, 27 | Row2: RowCon, 28 | Row1: ToRow, 29 | N: Prism, 30 | { 31 | unsafe_create_session::, _, _>( 32 | move |ctx, client_end_sum_sender| async move { 33 | let (provider_end, client_end) = A::create_endpoints(); 34 | 35 | let client_end_sum = N::inject_elem(App::new(client_end)); 36 | 37 | client_end_sum_sender.send(client_end_sum).unwrap(); 38 | 39 | unsafe_run_session(cont, ctx, provider_end).await; 40 | }, 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/choice/mod.rs: -------------------------------------------------------------------------------- 1 | mod external; 2 | mod internal; 3 | mod run_cont; 4 | 5 | pub use self::{ 6 | external::{ 7 | choose, 8 | offer_choice, 9 | }, 10 | internal::{ 11 | case, 12 | offer_case, 13 | }, 14 | run_cont::{ 15 | run_cont, 16 | RunCont, 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/choice/run_cont.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::base::*; 2 | 3 | pub trait RunCont 4 | where 5 | C: Context, 6 | A: Protocol, 7 | { 8 | type Ret; 9 | 10 | fn run_cont( 11 | self, 12 | cont: PartialSession, 13 | ) -> Self::Ret; 14 | } 15 | 16 | pub fn run_cont( 17 | runner: Runner, 18 | cont: PartialSession, 19 | ) -> Runner::Ret 20 | where 21 | C: Context, 22 | A: Protocol, 23 | Runner: RunCont, 24 | { 25 | runner.run_cont(cont) 26 | } 27 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/context.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::{ 2 | base::{ 3 | unsafe_create_session, 4 | unsafe_run_session, 5 | AppendContext, 6 | Empty, 7 | EmptyContext, 8 | PartialSession, 9 | Protocol, 10 | Session, 11 | Slot, 12 | }, 13 | functional::nat::{ 14 | Nat, 15 | S, 16 | Z, 17 | }, 18 | }; 19 | 20 | pub fn new_session(cont: Session) -> Session 21 | where 22 | A: Protocol, 23 | { 24 | cont 25 | } 26 | 27 | pub fn session(cont: PartialSession) -> Session 28 | where 29 | C: EmptyContext, 30 | A: Protocol, 31 | { 32 | unsafe_create_session(move |(), sender| async move { 33 | let ctx = ::empty_values(); 34 | 35 | unsafe_run_session(cont, ctx, sender).await; 36 | }) 37 | } 38 | 39 | pub fn partial_session(cont: Session) -> PartialSession 40 | where 41 | C: EmptyContext, 42 | A: Protocol, 43 | { 44 | unsafe_create_session(move |_, sender| async move { 45 | unsafe_run_session(cont, (), sender).await 46 | }) 47 | } 48 | 49 | pub fn append_emtpy_slot( 50 | cont: PartialSession 51 | ) -> PartialSession 52 | where 53 | A: Protocol, 54 | C: AppendContext<(Empty, ())>, 55 | { 56 | unsafe_create_session(move |ctx1, sender| async move { 57 | let (ctx2, _) = C::split_context(ctx1); 58 | unsafe_run_session(cont, ctx2, sender).await 59 | }) 60 | } 61 | 62 | pub fn session_1( 63 | cont: impl FnOnce(Z) -> PartialSession<(Empty, ()), A> 64 | ) -> Session 65 | where 66 | A: Protocol, 67 | { 68 | session(cont(Z::Value)) 69 | } 70 | 71 | pub fn session_2( 72 | cont: impl FnOnce(Z, S) -> PartialSession<(Empty, (Empty, ())), A> 73 | ) -> Session 74 | where 75 | A: Protocol, 76 | { 77 | session(cont(Z::Value, >::Value)) 78 | } 79 | 80 | pub fn partial_session_1( 81 | cont: impl FnOnce(Z) -> PartialSession<(A, ()), B> 82 | ) -> PartialSession<(A, ()), B> 83 | where 84 | A: Slot, 85 | B: Protocol, 86 | { 87 | cont(Z::Value) 88 | } 89 | 90 | pub fn partial_session_2( 91 | cont: impl FnOnce(Z, S) -> PartialSession<(A1, (A2, ())), B> 92 | ) -> PartialSession<(A1, (A2, ())), B> 93 | where 94 | A1: Slot, 95 | A2: Slot, 96 | B: Protocol, 97 | { 98 | cont(Z::Value, >::Value) 99 | } 100 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/cut.rs: -------------------------------------------------------------------------------- 1 | use tokio::{ 2 | task, 3 | try_join, 4 | }; 5 | 6 | use crate::internal::{ 7 | base::{ 8 | unsafe_create_session, 9 | unsafe_run_session, 10 | AppendContext, 11 | Context, 12 | Empty, 13 | PartialSession, 14 | Protocol, 15 | Slot, 16 | }, 17 | functional::{ 18 | App, 19 | Nat, 20 | }, 21 | }; 22 | 23 | pub enum L {} 24 | 25 | pub enum R {} 26 | 27 | pub enum AllLeft {} 28 | 29 | pub enum AllRight {} 30 | 31 | pub trait SplitContext 32 | where 33 | C: Context, 34 | { 35 | type Left: Context; 36 | 37 | type Right: Context; 38 | 39 | fn split_endpoints( 40 | ctx: C::Endpoints 41 | ) -> ( 42 | ::Endpoints, 43 | ::Endpoints, 44 | ); 45 | } 46 | 47 | impl SplitContext<()> for () 48 | { 49 | type Left = (); 50 | type Right = (); 51 | 52 | fn split_endpoints(_: ()) -> ((), ()) 53 | { 54 | ((), ()) 55 | } 56 | } 57 | 58 | impl SplitContext for AllLeft 59 | where 60 | C: Context, 61 | { 62 | type Left = C; 63 | type Right = (); 64 | 65 | fn split_endpoints(ctx: C::Endpoints) -> (C::Endpoints, ()) 66 | { 67 | (ctx, ()) 68 | } 69 | } 70 | 71 | impl SplitContext for AllRight 72 | where 73 | C: Context, 74 | { 75 | type Left = (); 76 | type Right = C; 77 | 78 | fn split_endpoints(ctx: C::Endpoints) -> ((), C::Endpoints) 79 | { 80 | ((), ctx) 81 | } 82 | } 83 | 84 | impl SplitContext<(Empty, C)> for (Empty, X) 85 | where 86 | C: Context, 87 | C1: Context, 88 | C2: Context, 89 | X: SplitContext, 90 | { 91 | type Left = (Empty, C1); 92 | type Right = (Empty, C2); 93 | 94 | fn split_endpoints( 95 | (a, ctx): ((), C::Endpoints) 96 | ) -> (((), C1::Endpoints), ((), C2::Endpoints)) 97 | { 98 | let (ctx1, ctx2) = X::split_endpoints(ctx); 99 | 100 | ((a, ctx1), ((), ctx2)) 101 | } 102 | } 103 | 104 | impl SplitContext<(A, C)> for (L, X) 105 | where 106 | A: Slot, 107 | C: Context, 108 | C1: Context, 109 | C2: Context, 110 | X: SplitContext, 111 | { 112 | type Left = (A, C1); 113 | type Right = (Empty, C2); 114 | 115 | fn split_endpoints( 116 | (a, ctx): (A::Endpoint, C::Endpoints) 117 | ) -> ((A::Endpoint, C1::Endpoints), ((), C2::Endpoints)) 118 | { 119 | let (ctx1, ctx2) = X::split_endpoints(ctx); 120 | 121 | ((a, ctx1), ((), ctx2)) 122 | } 123 | } 124 | 125 | impl SplitContext<(A, C)> for (R, X) 126 | where 127 | A: Slot, 128 | C: Context, 129 | C1: Context, 130 | C2: Context, 131 | X: SplitContext, 132 | { 133 | type Left = (Empty, C1); 134 | type Right = (A, C2); 135 | 136 | fn split_endpoints( 137 | (a, ctx): (A::Endpoint, C::Endpoints) 138 | ) -> (((), C1::Endpoints), (A::Endpoint, C2::Endpoints)) 139 | { 140 | let (ctx1, ctx2) = X::split_endpoints(ctx); 141 | 142 | (((), ctx1), (a, ctx2)) 143 | } 144 | } 145 | 146 | pub trait Cut: SplitContext 147 | where 148 | C: Context, 149 | { 150 | fn cut( 151 | cont1: PartialSession, 152 | cont2: impl FnOnce( 153 | ::Length, 154 | ) -> PartialSession< 155 | >::Appended, 156 | B, 157 | >, 158 | ) -> PartialSession 159 | where 160 | A: Protocol, 161 | B: Protocol, 162 | Self::Right: AppendContext<(A, ())>; 163 | } 164 | 165 | impl Cut for X 166 | where 167 | C: Context, 168 | X: SplitContext, 169 | { 170 | fn cut( 171 | cont1: PartialSession, 172 | cont2: impl FnOnce( 173 | ::Length, 174 | ) -> PartialSession< 175 | >::Appended, 176 | B, 177 | >, 178 | ) -> PartialSession 179 | where 180 | A: Protocol, 181 | B: Protocol, 182 | Self::Right: AppendContext<(A, ())>, 183 | { 184 | cut::(cont1, cont2) 185 | } 186 | } 187 | 188 | pub fn cut( 189 | cont1: PartialSession, 190 | cont2: Func, 191 | ) -> PartialSession 192 | where 193 | A: Protocol, 194 | B: Protocol, 195 | C: Context, 196 | C1: Context, 197 | C2: Context, 198 | X: SplitContext, 199 | C2: AppendContext<(A, ())>, 200 | Func: FnOnce(C2::Length) -> PartialSession, 201 | { 202 | let cont3 = cont2(C2::Length::nat()); 203 | 204 | unsafe_create_session(move |ctx, sender1| async move { 205 | let (ctx1, ctx2) = X::split_endpoints(ctx); 206 | 207 | let (provider_end_a, client_end_a) = A::create_endpoints(); 208 | 209 | let ctx3 = C2::append_context(ctx2, (App::new(client_end_a), ())); 210 | 211 | let child1 = task::spawn(async move { 212 | unsafe_run_session(cont3, ctx3, sender1).await; 213 | }); 214 | 215 | let child2 = task::spawn(async { 216 | unsafe_run_session(cont1, ctx1, provider_end_a).await; 217 | }); 218 | 219 | try_join!(child1, child2).unwrap(); 220 | }) 221 | } 222 | 223 | /* 224 | Cut (Communication) 225 | 226 | cont1 :: Δ1, Q, Δ2 ⊢ P cont2 :: Δ3 ⊢ Q 227 | ============================================== 228 | link(cont1, cont2) :: Δ1, Δ2, Δ3 ⊢ P 229 | */ 230 | 231 | pub fn cut_append( 232 | cont1: PartialSession, 233 | cont2: PartialSession, 234 | ) -> PartialSession 235 | where 236 | A: Protocol, 237 | B: Protocol, 238 | C1: Context, 239 | C2: Context, 240 | C3: Context, 241 | C4: Context, 242 | C1: AppendContext<(A, ()), Appended = C3>, 243 | C1: AppendContext, 244 | { 245 | unsafe_create_session(move |ctx1, b_sender| async move { 246 | let (ctx2, ctx3) = >::split_context(ctx1); 247 | 248 | let (provider_end_a, client_end_a) = A::create_endpoints(); 249 | 250 | let ctx4 = >::append_context( 251 | ctx2, 252 | (App::new(client_end_a), ()), 253 | ); 254 | 255 | let child1 = task::spawn(async { 256 | unsafe_run_session(cont1, ctx4, b_sender).await; 257 | }); 258 | 259 | let child2 = task::spawn(async { 260 | unsafe_run_session(cont2, ctx3, provider_end_a).await; 261 | }); 262 | 263 | try_join!(child1, child2).unwrap(); 264 | }) 265 | } 266 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/end.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | 3 | use crate::internal::{ 4 | base::{ 5 | unsafe_create_session, 6 | unsafe_run_session, 7 | Context, 8 | ContextLens, 9 | Empty, 10 | EmptyContext, 11 | PartialSession, 12 | Protocol, 13 | Session, 14 | }, 15 | protocol::End, 16 | }; 17 | 18 | /* 19 | 20 | cleaner() :: () 21 | =============================== 22 | terminate_async (cleaner) :: · ⊢ 1 23 | 24 | Create a unit protocol (1) out of nothing. 25 | */ 26 | 27 | pub fn terminate_async(cleaner: Func) -> PartialSession 28 | where 29 | C: EmptyContext, 30 | Func: FnOnce() -> Fut + Send + 'static, 31 | Fut: Future + Send, 32 | { 33 | unsafe_create_session::(move |_, sender| async move { 34 | cleaner().await; 35 | 36 | sender.send(()).unwrap(); 37 | }) 38 | } 39 | 40 | pub fn terminate() -> PartialSession 41 | where 42 | C: EmptyContext, 43 | { 44 | terminate_async(|| async {}) 45 | } 46 | 47 | pub fn terminate_nil() -> Session 48 | { 49 | terminate() 50 | } 51 | 52 | /* 53 | cont :: Δ ⊢ P 54 | =========================== 55 | wait_async (cont) :: 1, Δ ⊢ P 56 | 57 | Wait for a given input protocol to terminate, then continue as P. 58 | */ 59 | 60 | pub fn wait( 61 | _: N, 62 | cont: PartialSession, 63 | ) -> PartialSession 64 | where 65 | C: Context, 66 | A: Protocol, 67 | N: ContextLens, 68 | { 69 | unsafe_create_session(move |ctx1, sender| async move { 70 | let (endpoint, ctx2) = N::extract_source(ctx1); 71 | 72 | let receiver = endpoint.get_applied(); 73 | 74 | let ctx3 = N::insert_target((), ctx2); 75 | 76 | receiver.recv().await.unwrap(); 77 | 78 | unsafe_run_session(cont, ctx3, sender).await; 79 | }) 80 | } 81 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/fix.rs: -------------------------------------------------------------------------------- 1 | use tokio::task; 2 | 3 | use crate::internal::{ 4 | base::*, 5 | functional::App, 6 | }; 7 | 8 | pub fn fix_session( 9 | cont: PartialSession 10 | ) -> PartialSession> 11 | where 12 | C: Context, 13 | R: Context, 14 | F: Protocol, 15 | A: Protocol, 16 | F: RecApp<(RecX, R), Applied = A>, 17 | { 18 | unsafe_create_session::, _, _>(move |ctx, sender1| async move { 19 | let (provider_end_a, client_end_a) = A::create_endpoints(); 20 | 21 | let rec_end = RecEndpoint { 22 | applied: Box::new(client_end_a), 23 | }; 24 | sender1.send(rec_end).unwrap(); 25 | 26 | task::spawn(async move { 27 | unsafe_run_session(cont, ctx, provider_end_a).await; 28 | }); 29 | }) 30 | } 31 | 32 | pub fn unfix_session( 33 | _n: N, 34 | cont: PartialSession, 35 | ) -> PartialSession 36 | where 37 | B: Protocol, 38 | C1: Context, 39 | C2: Context, 40 | F: Protocol, 41 | R: Context, 42 | F: RecApp<(RecX, R), Applied = A>, 43 | A: Protocol, 44 | N: ContextLens, A, Target = C2>, 45 | { 46 | unsafe_create_session::(move |ctx1, provider_end| async move { 47 | let (endpoint, ctx2) = N::extract_source(ctx1); 48 | 49 | let receiver1 = endpoint.get_applied(); 50 | 51 | let rec_end = receiver1.recv().await.unwrap(); 52 | 53 | let client_end = *rec_end.applied.get_applied(); 54 | 55 | let ctx3 = N::insert_target(App::new(client_end), ctx2); 56 | 57 | task::spawn(async move { 58 | unsafe_run_session(cont, ctx3, provider_end).await; 59 | }); 60 | }) 61 | } 62 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/forward.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::base::{ 2 | unsafe_create_session, 3 | Context, 4 | ContextLens, 5 | Empty, 6 | EmptyContext, 7 | PartialSession, 8 | Protocol, 9 | }; 10 | 11 | pub fn forward(_: N) -> PartialSession 12 | where 13 | A: Protocol, 14 | C: Context, 15 | N::Target: EmptyContext, 16 | N: ContextLens, 17 | { 18 | unsafe_create_session::(move |ctx, provider_end| async move { 19 | let (client_end, _) = N::extract_source(ctx); 20 | A::forward(client_end.get_applied(), provider_end).await; 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/include.rs: -------------------------------------------------------------------------------- 1 | use std::collections::LinkedList; 2 | 3 | use crate::internal::{ 4 | base::{ 5 | AppendContext, 6 | Context, 7 | ContextLens, 8 | Empty, 9 | PartialSession, 10 | Protocol, 11 | Session, 12 | }, 13 | protocol::End, 14 | session::{ 15 | context::append_emtpy_slot, 16 | cut::{ 17 | AllRight, 18 | Cut, 19 | }, 20 | end::{ 21 | terminate, 22 | wait, 23 | }, 24 | }, 25 | }; 26 | 27 | pub fn include_session( 28 | session: Session, 29 | cont: impl FnOnce(N) -> PartialSession, 30 | ) -> PartialSession 31 | where 32 | A: Protocol, 33 | B: Protocol, 34 | C1: Context, 35 | C2: Context, 36 | C1: AppendContext<(A, ()), Appended = C2>, 37 | { 38 | AllRight::cut(session, cont) 39 | } 40 | 41 | pub fn wait_session( 42 | session1: Session, 43 | cont: PartialSession, 44 | ) -> PartialSession 45 | where 46 | P: Protocol, 47 | I: Context, 48 | I: AppendContext<(End, ())>, 49 | I: AppendContext<(Empty, ())>, 50 | I::Length: ContextLens< 51 | >::Appended, 52 | End, 53 | Empty, 54 | Target = >::Appended, 55 | >, 56 | { 57 | include_session(session1, move |chan| wait(chan, append_emtpy_slot(cont))) 58 | } 59 | 60 | pub fn wait_sessions( 61 | sessions: Vec>, 62 | cont: PartialSession, 63 | ) -> PartialSession 64 | where 65 | P: Protocol, 66 | I: AppendContext<(End, ())>, 67 | I: AppendContext<(Empty, ())>, 68 | I::Length: ContextLens< 69 | >::Appended, 70 | End, 71 | Empty, 72 | Target = >::Appended, 73 | >, 74 | { 75 | wait_session(join_sessions(sessions), cont) 76 | } 77 | 78 | pub fn join_sessions(sessions: Vec>) -> Session 79 | { 80 | do_join_sessions(sessions.into_iter().collect()) 81 | } 82 | 83 | fn do_join_sessions(mut sessions: LinkedList>) -> Session 84 | { 85 | match sessions.pop_front() { 86 | Some(session) => include_session(session, move |c1| { 87 | include_session(do_join_sessions(sessions), move |c2| { 88 | wait(c1, wait(c2, terminate())) 89 | }) 90 | }), 91 | None => terminate(), 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod public; 2 | 3 | mod apply; 4 | mod channel; 5 | mod choice; 6 | mod context; 7 | mod cut; 8 | mod end; 9 | mod fix; 10 | mod forward; 11 | mod include; 12 | mod run; 13 | mod shared; 14 | mod step; 15 | mod value; 16 | mod wrap; 17 | 18 | #[doc(inline)] 19 | pub use self::{ 20 | apply::{ 21 | apply_channel, 22 | send_channel_to_session, 23 | }, 24 | channel::{ 25 | fork, 26 | receive_channel, 27 | receive_channel_from, 28 | send_channel_from, 29 | send_channel_to, 30 | }, 31 | choice::{ 32 | case, 33 | choose, 34 | offer_case, 35 | offer_choice, 36 | run_cont, 37 | RunCont, 38 | }, 39 | context::{ 40 | append_emtpy_slot, 41 | new_session, 42 | partial_session, 43 | partial_session_1, 44 | partial_session_2, 45 | session, 46 | session_1, 47 | session_2, 48 | }, 49 | cut::{ 50 | cut, 51 | cut_append, 52 | AllLeft, 53 | AllRight, 54 | Cut, 55 | L, 56 | R, 57 | }, 58 | end::{ 59 | terminate, 60 | terminate_async, 61 | terminate_nil, 62 | wait, 63 | }, 64 | fix::{ 65 | fix_session, 66 | unfix_session, 67 | }, 68 | forward::forward, 69 | include::{ 70 | include_session, 71 | join_sessions, 72 | wait_session, 73 | wait_sessions, 74 | }, 75 | run::{ 76 | run_session, 77 | run_session_with_result, 78 | run_shared_session, 79 | run_shared_session_with_join_handle, 80 | }, 81 | shared::{ 82 | accept_shared_session, 83 | acquire_shared_session, 84 | async_acquire_shared_session, 85 | async_acquire_shared_session_with_result, 86 | detach_shared_session, 87 | release_shared_session, 88 | shared_forward, 89 | }, 90 | step::step, 91 | value::{ 92 | receive_value, 93 | receive_value_from, 94 | send_value, 95 | send_value_to, 96 | }, 97 | wrap::{ 98 | unwrap_session, 99 | wrap_session, 100 | }, 101 | }; 102 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/public.rs: -------------------------------------------------------------------------------- 1 | #[doc(inline)] 2 | pub use super::{ 3 | accept_shared_session, 4 | acquire_shared_session, 5 | append_emtpy_slot, 6 | apply_channel, 7 | async_acquire_shared_session, 8 | async_acquire_shared_session_with_result, 9 | case, 10 | choose, 11 | cut, 12 | cut_append, 13 | detach_shared_session, 14 | fix_session, 15 | fork, 16 | forward, 17 | include_session, 18 | join_sessions, 19 | new_session, 20 | offer_case, 21 | offer_choice, 22 | partial_session, 23 | partial_session_1, 24 | partial_session_2, 25 | receive_channel, 26 | receive_channel_from, 27 | receive_value, 28 | receive_value_from, 29 | release_shared_session, 30 | run_cont, 31 | run_session, 32 | run_session_with_result, 33 | run_shared_session, 34 | run_shared_session_with_join_handle, 35 | send_channel_from, 36 | send_channel_to, 37 | send_channel_to_session, 38 | send_value, 39 | send_value_to, 40 | session, 41 | session_1, 42 | session_2, 43 | shared_forward, 44 | step, 45 | terminate, 46 | terminate_async, 47 | terminate_nil, 48 | unfix_session, 49 | unwrap_session, 50 | wait, 51 | wait_session, 52 | wait_sessions, 53 | wrap_session, 54 | AllLeft, 55 | AllRight, 56 | Cut, 57 | L, 58 | R, 59 | }; 60 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/run.rs: -------------------------------------------------------------------------------- 1 | use tokio::{ 2 | task, 3 | try_join, 4 | }; 5 | 6 | use crate::internal::{ 7 | base::{ 8 | once_channel, 9 | unbounded, 10 | unsafe_create_shared_channel, 11 | unsafe_run_session, 12 | unsafe_run_shared_session, 13 | Protocol, 14 | Session, 15 | SharedChannel, 16 | SharedProtocol, 17 | SharedSession, 18 | Value, 19 | }, 20 | protocol::{ 21 | End, 22 | SendValue, 23 | }, 24 | }; 25 | 26 | pub async fn run_session(session: Session) 27 | { 28 | let (sender, receiver) = once_channel(); 29 | 30 | let child1 = task::spawn(async move { 31 | unsafe_run_session(session, (), sender).await; 32 | }); 33 | 34 | let child2 = task::spawn(async move { 35 | receiver.recv().await.unwrap(); 36 | }); 37 | 38 | try_join!(child1, child2).unwrap(); 39 | } 40 | 41 | pub async fn run_session_with_result( 42 | session: Session> 43 | ) -> T 44 | where 45 | T: Send + 'static, 46 | { 47 | let (provider_end, val_receiver) = >::create_endpoints(); 48 | 49 | let child1 = task::spawn(async move { 50 | unsafe_run_session(session, (), provider_end).await; 51 | }); 52 | 53 | let (Value(val), end_receiver) = val_receiver.recv().await.unwrap(); 54 | 55 | end_receiver.recv().await.unwrap(); 56 | 57 | let _ = child1.await; 58 | 59 | val 60 | } 61 | 62 | pub fn run_shared_session(session: SharedSession) -> SharedChannel 63 | where 64 | A: SharedProtocol, 65 | { 66 | let (chan, _) = run_shared_session_with_join_handle(session); 67 | 68 | chan 69 | } 70 | 71 | pub fn run_shared_session_with_join_handle( 72 | session: SharedSession 73 | ) -> (SharedChannel, task::JoinHandle<()>) 74 | where 75 | A: SharedProtocol, 76 | { 77 | let (sender1, receiver1) = unbounded(); 78 | 79 | let (session2, receiver2) = unsafe_create_shared_channel(); 80 | 81 | task::spawn(async move { 82 | info!("[run_shared_session] exec_shared_session"); 83 | 84 | unsafe_run_shared_session(session, receiver1).await; 85 | 86 | info!("[run_shared_session] exec_shared_session returned"); 87 | }); 88 | 89 | let handle = task::spawn(async move { 90 | loop { 91 | let m_senders = receiver2.recv().await; 92 | 93 | debug!("[run_shared_session] received sender3"); 94 | 95 | match m_senders { 96 | Some(senders) => { 97 | sender1.send(senders).unwrap(); 98 | } 99 | None => { 100 | info!("[run_shared_session] terminating shared session"); 101 | 102 | return; 103 | } 104 | } 105 | } 106 | }); 107 | 108 | (session2, handle) 109 | } 110 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/shared/accept.rs: -------------------------------------------------------------------------------- 1 | use core::future::Future; 2 | 3 | use crate::internal::{ 4 | base::*, 5 | functional::*, 6 | protocol::{ 7 | LinearToShared, 8 | Lock, 9 | SharedToLinear, 10 | }, 11 | }; 12 | 13 | pub fn accept_shared_session( 14 | cont: impl Future, ()), F::Applied>> 15 | + Send 16 | + 'static 17 | ) -> SharedSession> 18 | where 19 | F: Protocol, 20 | F: SharedRecApp>>, 21 | F::Applied: Protocol, 22 | { 23 | unsafe_create_shared_session( 24 | move |receiver1: Receiver<( 25 | SenderOnce<()>, 26 | SenderOnce>, 27 | )>| async move { 28 | let (lock_producer_end, lock_client_end) = >::create_endpoints(); 29 | 30 | let (producer_end, client_end) = F::Applied::create_endpoints(); 31 | 32 | let m_sender1 = receiver1.recv().await; 33 | 34 | if let Some((sender5, sender6)) = m_sender1 { 35 | sender6 36 | .send(LinearToShared { 37 | linear: Box::new(client_end), 38 | }) 39 | .unwrap(); 40 | 41 | sender5.send(()).unwrap(); 42 | 43 | lock_producer_end.send(Lock { unlock: receiver1 }).unwrap(); 44 | 45 | debug!("[accept_shared_session] calling cont"); 46 | 47 | unsafe_run_session( 48 | cont.await, 49 | (App::new(lock_client_end), ()), 50 | producer_end, 51 | ) 52 | .await; 53 | 54 | debug!("[accept_shared_session] returned from cont"); 55 | } else { 56 | // shared session is terminated with all references to it 57 | // being dropped 58 | } 59 | }, 60 | ) 61 | } 62 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/shared/acquire.rs: -------------------------------------------------------------------------------- 1 | use tokio::task; 2 | 3 | use crate::internal::{ 4 | base::*, 5 | functional::*, 6 | protocol::{ 7 | End, 8 | LinearToShared, 9 | SendValue, 10 | SharedToLinear, 11 | }, 12 | }; 13 | 14 | pub fn async_acquire_shared_session( 15 | shared: SharedChannel>, 16 | cont1: impl FnOnce(Z) -> PartialSession<(F::Applied, ()), End> + Send + 'static, 17 | ) -> task::JoinHandle<()> 18 | where 19 | F: Protocol, 20 | F: SharedRecApp>>, 21 | F::Applied: Protocol, 22 | { 23 | debug!("[async_acquire_shared_session] acquiring shared session"); 24 | 25 | let (receiver3, receiver4) = unsafe_receive_shared_channel(shared); 26 | 27 | task::spawn(async move { 28 | let (provider_end_1, client_end_1) = End::create_endpoints(); 29 | 30 | let LinearToShared { linear } = receiver4.recv().await.unwrap(); 31 | 32 | let client_end_2 = linear.get_applied(); 33 | 34 | let cont2 = cont1(Z); 35 | 36 | let ctx = (App::new(client_end_2), ()); 37 | 38 | unsafe_run_session(cont2, ctx, provider_end_1).await; 39 | 40 | client_end_1.recv().await.unwrap(); 41 | 42 | receiver3.recv().await.unwrap(); 43 | }) 44 | } 45 | 46 | pub fn async_acquire_shared_session_with_result( 47 | shared: SharedChannel>, 48 | cont1: impl FnOnce(Z) -> PartialSession<(F::Applied, ()), SendValue> 49 | + Send 50 | + 'static, 51 | ) -> task::JoinHandle 52 | where 53 | F: Protocol, 54 | T: Send + 'static, 55 | F: SharedRecApp>>, 56 | F::Applied: Protocol, 57 | { 58 | debug!("[async_acquire_shared_session_with_result] acquiring shared session"); 59 | 60 | let (receiver3, receiver4) = unsafe_receive_shared_channel(shared); 61 | 62 | task::spawn(async move { 63 | let (provider_end_1, client_end_1) = 64 | >::create_endpoints(); 65 | 66 | let LinearToShared { linear } = receiver4.recv().await.unwrap(); 67 | 68 | let client_end_2 = linear.get_applied(); 69 | 70 | let cont2 = cont1(Z); 71 | 72 | let ctx = (App::new(client_end_2), ()); 73 | 74 | unsafe_run_session(cont2, ctx, provider_end_1).await; 75 | 76 | receiver3.recv().await.unwrap(); 77 | 78 | let (Value(val), end_receiver) = client_end_1.recv().await.unwrap(); 79 | 80 | end_receiver.recv().await.unwrap(); 81 | 82 | val 83 | }) 84 | } 85 | 86 | pub fn acquire_shared_session( 87 | shared: SharedChannel>, 88 | cont1: impl FnOnce(C::Length) -> PartialSession + Send + 'static, 89 | ) -> PartialSession 90 | where 91 | C: Context, 92 | F: Protocol, 93 | A: Protocol, 94 | F::Applied: Protocol, 95 | F: SharedRecApp>>, 96 | C: AppendContext<(F::Applied, ())>, 97 | { 98 | unsafe_create_session(move |ctx1, provider_end_1| async move { 99 | let cont2 = cont1(C::Length::nat()); 100 | 101 | let (receiver3, receiver4) = unsafe_receive_shared_channel(shared); 102 | 103 | debug!("[acquire_shared_session] acquiring shared endpoint"); 104 | 105 | receiver3.recv().await.unwrap(); 106 | 107 | debug!("[acquire_shared_session] acquired shared endpoint"); 108 | 109 | let LinearToShared { linear } = receiver4.recv().await.unwrap(); 110 | 111 | let client_end_2 = linear.get_applied(); 112 | 113 | let ctx2 = C::append_context(ctx1, (App::new(client_end_2), ())); 114 | 115 | unsafe_run_session(cont2, ctx2, provider_end_1).await; 116 | }) 117 | } 118 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/shared/detach.rs: -------------------------------------------------------------------------------- 1 | use tokio::task; 2 | 3 | use crate::internal::{ 4 | base::*, 5 | protocol::{ 6 | LinearToShared, 7 | Lock, 8 | SharedToLinear, 9 | }, 10 | }; 11 | 12 | pub fn detach_shared_session( 13 | cont: SharedSession> 14 | ) -> PartialSession<(Lock, C), SharedToLinear>> 15 | where 16 | F: Protocol, 17 | F: SharedRecApp>>, 18 | F::Applied: Protocol, 19 | C: EmptyContext, 20 | { 21 | unsafe_create_session::<(Lock, C), SharedToLinear>, _, _>( 22 | move |(lock_client_end, _), receiver| async move { 23 | debug!("[detach_shared_session] receiving sender2"); 24 | 25 | let lock_receiver = lock_client_end.get_applied(); 26 | 27 | let Lock { unlock: receiver2 } = lock_receiver.recv().await.unwrap(); 28 | 29 | receiver.recv().await.unwrap(); 30 | 31 | debug!("[detach_shared_session] received sender2"); 32 | 33 | // Run the continuation as a separate task *without* awaiting to 34 | // avoice stack overflow in the async worker thread. 35 | task::spawn(async move { 36 | unsafe_run_shared_session(cont, receiver2).await; 37 | }) 38 | .await 39 | .unwrap(); 40 | 41 | debug!("[detach_shared_session] ran cont"); 42 | }, 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/shared/forward.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::{ 2 | base::*, 3 | protocol::{ 4 | LinearToShared, 5 | Lock, 6 | SharedToLinear, 7 | }, 8 | }; 9 | 10 | pub fn shared_forward( 11 | channel: SharedChannel> 12 | ) -> PartialSession<(Lock, C), SharedToLinear>> 13 | where 14 | A1: Protocol, 15 | A2: Protocol, 16 | A1: SharedRecApp>, Applied = A2>, 17 | C: EmptyContext, 18 | { 19 | unsafe_create_session::<(Lock, C), SharedToLinear>, _, _>( 20 | move |(lock_client_end, _), receiver1| async move { 21 | let lock_receiver = lock_client_end.get_applied(); 22 | 23 | let Lock { unlock } = lock_receiver.recv().await.unwrap(); 24 | 25 | receiver1.recv().await.unwrap(); 26 | 27 | unsafe_forward_shared_channel(channel, unlock).await; 28 | }, 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/shared/mod.rs: -------------------------------------------------------------------------------- 1 | mod accept; 2 | mod acquire; 3 | mod detach; 4 | mod forward; 5 | mod release; 6 | 7 | pub use accept::*; 8 | pub use acquire::*; 9 | pub use detach::*; 10 | pub use forward::*; 11 | pub use release::*; 12 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/shared/release.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::{ 2 | base::*, 3 | protocol::{ 4 | LinearToShared, 5 | SharedToLinear, 6 | }, 7 | }; 8 | 9 | pub fn release_shared_session( 10 | _n: N, 11 | cont: PartialSession, 12 | ) -> PartialSession 13 | where 14 | A: Protocol, 15 | B: Protocol, 16 | C1: Context, 17 | C2: Context, 18 | A: SharedRecApp>>, 19 | N: ContextLens>, Empty, Target = C2>, 20 | { 21 | unsafe_create_session(move |ctx1, provider_end_b| async move { 22 | let (endpoint, ctx2) = N::extract_source(ctx1); 23 | 24 | let lock_sender = endpoint.get_applied(); 25 | 26 | let ctx3 = N::insert_target((), ctx2); 27 | 28 | lock_sender.send(()).unwrap(); 29 | 30 | unsafe_run_session(cont, ctx3, provider_end_b).await; 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/step.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | 3 | use crate::internal::base::*; 4 | 5 | pub fn step( 6 | cont1: impl Future> + Send + 'static 7 | ) -> PartialSession 8 | where 9 | C: Context, 10 | A: Protocol, 11 | { 12 | unsafe_create_session(move |ins, sender| async move { 13 | let cont2 = cont1.await; 14 | 15 | unsafe_run_session(cont2, ins, sender).await; 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/value/mod.rs: -------------------------------------------------------------------------------- 1 | mod receive; 2 | mod send; 3 | 4 | pub use receive::{ 5 | receive_value, 6 | send_value_to, 7 | }; 8 | pub use send::{ 9 | receive_value_from, 10 | send_value, 11 | }; 12 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/value/receive.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::{ 2 | base::{ 3 | unsafe_create_session, 4 | unsafe_run_session, 5 | Context, 6 | ContextLens, 7 | PartialSession, 8 | Protocol, 9 | Value, 10 | }, 11 | functional::App, 12 | protocol::ReceiveValue, 13 | }; 14 | 15 | pub fn receive_value( 16 | cont: impl FnOnce(T) -> PartialSession + Send + 'static 17 | ) -> PartialSession> 18 | where 19 | T: Send + 'static, 20 | A: Protocol, 21 | C: Context, 22 | { 23 | unsafe_create_session::, _, _>( 24 | move |ctx, receiver1| async move { 25 | let (Value(val), provider_end) = receiver1.recv().await.unwrap(); 26 | 27 | let cont2 = cont(val); 28 | 29 | unsafe_run_session(cont2, ctx, provider_end).await; 30 | }, 31 | ) 32 | } 33 | 34 | pub fn send_value_to( 35 | _n: N, 36 | val: T, 37 | cont: PartialSession, 38 | ) -> PartialSession 39 | where 40 | A: Protocol, 41 | B: Protocol, 42 | C1: Context, 43 | C2: Context, 44 | T: Send + 'static, 45 | N: ContextLens, B, Target = C2>, 46 | { 47 | unsafe_create_session(move |ctx1, provider_end_a| async move { 48 | let (endpoint, ctx2) = N::extract_source(ctx1); 49 | 50 | let (provider_end_b, client_end_b) = B::create_endpoints(); 51 | 52 | let sender1 = endpoint.get_applied(); 53 | 54 | let ctx3 = N::insert_target(App::new(client_end_b), ctx2); 55 | 56 | sender1.send((Value(val), provider_end_b)).unwrap(); 57 | 58 | unsafe_run_session(cont, ctx3, provider_end_a).await; 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/value/send.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::{ 2 | base::{ 3 | unsafe_create_session, 4 | unsafe_run_session, 5 | Context, 6 | ContextLens, 7 | PartialSession, 8 | Protocol, 9 | Value, 10 | }, 11 | functional::App, 12 | protocol::SendValue, 13 | }; 14 | 15 | pub fn send_value( 16 | val: T, 17 | cont: PartialSession, 18 | ) -> PartialSession> 19 | where 20 | T: Send + 'static, 21 | A: Protocol, 22 | C: Context, 23 | { 24 | unsafe_create_session::, _, _>( 25 | move |ctx, sender1| async move { 26 | let (provider_end, client_end) = A::create_endpoints(); 27 | sender1.send((Value(val), client_end)).unwrap(); 28 | 29 | unsafe_run_session(cont, ctx, provider_end).await; 30 | }, 31 | ) 32 | } 33 | 34 | pub fn receive_value_from( 35 | _n: N, 36 | cont: impl FnOnce(T) -> PartialSession + Send + 'static, 37 | ) -> PartialSession 38 | where 39 | A: Protocol, 40 | B: Protocol, 41 | C1: Context, 42 | C2: Context, 43 | T: Send + 'static, 44 | N: ContextLens, A, Target = C2>, 45 | { 46 | unsafe_create_session(move |ctx1, sender| async move { 47 | let (endpoint, ctx2) = N::extract_source(ctx1); 48 | 49 | let receiver = endpoint.get_applied(); 50 | 51 | let (Value(val), client_end) = receiver.recv().await.unwrap(); 52 | 53 | let ctx3 = N::insert_target(App::new(client_end), ctx2); 54 | 55 | let cont2 = cont(val); 56 | 57 | unsafe_run_session(cont2, ctx3, sender).await; 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /ferrite-session/src/internal/session/wrap.rs: -------------------------------------------------------------------------------- 1 | use crate::internal::{ 2 | base::*, 3 | functional::App, 4 | protocol::*, 5 | }; 6 | 7 | pub fn wrap_session( 8 | cont: PartialSession 9 | ) -> PartialSession> 10 | where 11 | C: Context, 12 | T: Wrapper, 13 | T: Send + 'static, 14 | T::Unwrap: Protocol, 15 | { 16 | unsafe_create_session::, _, _>(move |ctx, sender1| async move { 17 | let (provider_end, client_end) = T::Unwrap::create_endpoints(); 18 | 19 | sender1 20 | .send(Wrap { 21 | unwrap: Box::new(client_end), 22 | }) 23 | .unwrap(); 24 | 25 | unsafe_run_session(cont, ctx, provider_end).await; 26 | }) 27 | } 28 | 29 | pub fn unwrap_session( 30 | _: N, 31 | cont: PartialSession, 32 | ) -> PartialSession 33 | where 34 | C: Context, 35 | A: Protocol, 36 | T: Wrapper + Send + 'static, 37 | N: ContextLens, T::Unwrap>, 38 | { 39 | unsafe_create_session(move |ctx1, provider_end_a| async move { 40 | let (endpoint, ctx2) = N::extract_source(ctx1); 41 | 42 | let receiver = endpoint.get_applied(); 43 | 44 | let wrapped = receiver.recv().await.unwrap(); 45 | 46 | let unwrapped = wrapped.unwrap.unwrap(); 47 | 48 | let ctx3 = N::insert_target(App::new(unwrapped), ctx2); 49 | 50 | unsafe_run_session(cont, ctx3, provider_end_a).await; 51 | }) 52 | } 53 | -------------------------------------------------------------------------------- /ferrite-session/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | 4 | pub mod internal; 5 | pub mod macros; 6 | 7 | #[doc(inline)] 8 | pub use internal::public::{ 9 | either, 10 | prelude, 11 | }; 12 | -------------------------------------------------------------------------------- /ferrite-session/src/macros.rs: -------------------------------------------------------------------------------- 1 | pub use paste::paste; 2 | 3 | #[macro_export] 4 | macro_rules! Sum { 5 | ( $(,)? ) => { 6 | $crate::choice::nary::Bottom 7 | }; 8 | ( $e:ty ) => { 9 | $crate::prelude::Sum < 10 | $e, 11 | $crate::prelude::Bottom 12 | > 13 | }; 14 | ( $e:ty, $($tail:tt)* ) => { 15 | $crate::prelude::Sum < $e, $crate::prelude::Sum!( $( $tail )* ) > 16 | }; 17 | } 18 | 19 | #[macro_export] 20 | macro_rules! HList { 21 | ( $(,)? ) => { 22 | () 23 | }; 24 | ( $e:ty ) => { 25 | ( $e, () ) 26 | }; 27 | ( $e:ty, $($tail:tt)* ) => { 28 | ( $e, $crate::prelude::HList!( $($tail)* ) ) 29 | }; 30 | } 31 | 32 | #[macro_export] 33 | macro_rules! match_choice_value { 34 | ( $choice:expr; $( $label:path => $e:expr $(,)? )+ ) => { 35 | match $crate::prelude::extract_choice( $choice ) { 36 | $( 37 | $label ( cont ) => { 38 | $crate::prelude::run_cont ( cont, 39 | $crate::prelude::step ( async move { 40 | $e 41 | }) 42 | ) 43 | } 44 | )* 45 | } 46 | } 47 | } 48 | 49 | #[macro_export] 50 | macro_rules! match_choice { 51 | ( $( $label:path => $e:expr $(,)? )+ ) => { 52 | move | ferrite_choice_internal__ | { 53 | $crate::match_choice_value! { ferrite_choice_internal__; 54 | $( $label => $e ),* 55 | } 56 | } 57 | }; 58 | } 59 | 60 | #[macro_export] 61 | macro_rules! offer_choice { 62 | ( $( $label:path => $e:expr $(,)? )+ ) => { 63 | $crate::prelude::offer_choice ( 64 | $crate::match_choice! { 65 | $( $label => $e ),* 66 | } 67 | ) 68 | } 69 | } 70 | 71 | #[macro_export] 72 | macro_rules! case { 73 | ( $chan:expr ; $( $label:path => $e:expr $(,)? )+ ) => { 74 | $crate::prelude::case ( $chan, 75 | $crate::match_choice! { 76 | $( $label => $e ),* 77 | } 78 | ) 79 | } 80 | } 81 | 82 | #[macro_export] 83 | macro_rules! define_choice_protocol { 84 | ( $name:ident ; 85 | $( $protocols:ty ),+ $(,)? 86 | ) => { 87 | pub enum $name {} 88 | 89 | impl $crate::prelude::ToRow for $name { 90 | type Row = $crate::prelude::HList![ $( $protocols ),* ]; 91 | } 92 | }; 93 | 94 | ( $name:ident 95 | < $( $types:ident ),+ $(,)? > ; 96 | $( $protocols:ty ),+ $(,)? 97 | ) => { 98 | pub struct $name <$( $types ),*> 99 | { 100 | phantom: std::marker::PhantomData<($( $types ),*)> 101 | } 102 | 103 | impl < $( $types ),* > 104 | $crate::prelude::ToRow for $name < $( $types ),* > 105 | { 106 | type Row = $crate::prelude::HList![ $( $protocols ),* ]; 107 | } 108 | }; 109 | } 110 | 111 | #[macro_export] 112 | macro_rules! define_choice_labels { 113 | ( $( $labels:ident ),+ $(,)? ) => { 114 | $crate::define_choice_labels![ $crate::prelude::Z; $( $labels ),* ]; 115 | }; 116 | ( $acc:ty; $label:ident ) => { 117 | $crate::macros::paste! { 118 | #[allow(non_upper_case_globals)] 119 | pub const [< $label Label >] 120 | : $crate::prelude::ChoiceSelector < $acc > = 121 | < $crate::prelude::ChoiceSelector < $acc > >::new(); 122 | } 123 | }; 124 | ( $acc:ty; $label:ident, $( $labels:ident ),+ ) => { 125 | $crate::macros::paste! { 126 | #[allow(non_upper_case_globals)] 127 | pub const [< $label Label >] 128 | : $crate::prelude::ChoiceSelector < $acc > = 129 | < $crate::prelude::ChoiceSelector < $acc > >::new(); 130 | 131 | $crate::define_choice_labels![ 132 | $crate::prelude::S < $acc >; 133 | $( $labels ),* 134 | ]; 135 | } 136 | }; 137 | } 138 | 139 | #[macro_export] 140 | macro_rules! define_choice_enum { 141 | ( $name:ident; $( $labels:ident ),+ $(,)? ) => { 142 | $crate::macros::paste! { 143 | pub enum [< $name Choice >] 144 | < $( [< $labels T >] ),* > 145 | { 146 | $( $labels ( [< $labels T >] ) ),* 147 | } 148 | 149 | pub use [< $name Choice >] :: { 150 | $( $labels ),* 151 | }; 152 | } 153 | } 154 | } 155 | 156 | #[macro_export] 157 | #[allow(unused_macros)] 158 | 159 | macro_rules! match_extract { 160 | ( $x:ident ; 161 | ) => { 162 | match $x {} 163 | }; 164 | ( $x:ident ; 165 | $label:ident 166 | ) => { 167 | $crate::macros::paste! { 168 | match $x { 169 | $crate::prelude::Sum::Inl ( [< $label:snake >] ) => { 170 | $label ( [< $label:snake >] ) 171 | } 172 | $crate::prelude::Sum::Inr ( bot ) => { 173 | match bot { } 174 | } 175 | } 176 | } 177 | }; 178 | ( $x:ident ; 179 | $label:ident, $( $labels:ident ),* $(,)? 180 | ) => { 181 | $crate::macros::paste! { 182 | match $x { 183 | $crate::prelude::Sum::Inl ( [< $label:snake >] ) => { 184 | $label ( [< $label:snake >] ) 185 | } 186 | $crate::prelude::Sum::Inr ( [< $label:snake _rest >] ) => { 187 | $crate::match_extract! { 188 | [< $label:snake _rest >] ; 189 | $( $labels ),* 190 | } 191 | } 192 | } 193 | } 194 | }; 195 | } 196 | 197 | #[macro_export] 198 | macro_rules! define_extract_choice { 199 | ( $name:ident ; 200 | $( $labels:ident ),* $(,)? 201 | ) => { 202 | $crate::macros::paste! { 203 | impl < $( [< $labels T >] ),* > 204 | std::convert::From < 205 | $crate::prelude::Sum![ $( [< $labels T >] ),* ] 206 | > 207 | for [< $name Choice >] 208 | < $( [< $labels T >] ),* > 209 | { 210 | fn from 211 | (row: $crate::prelude::Sum![ $( [< $labels T >] ),* ] ) 212 | -> Self 213 | { 214 | $crate::match_extract! { 215 | row ; 216 | $( $labels ),* 217 | } 218 | } 219 | } 220 | } 221 | } 222 | } 223 | 224 | #[macro_export] 225 | macro_rules! define_choice { 226 | ( $name:ident ; 227 | $( $labels:ident : $protocols:ty ),+ 228 | $(,)? 229 | ) => { 230 | $crate::define_choice_protocol![ $name ; 231 | $( $protocols ),* 232 | ]; 233 | 234 | $crate::define_choice_labels![ 235 | $( $labels ),* 236 | ]; 237 | 238 | $crate::define_choice_enum![ $name ; 239 | $( $labels ),* 240 | ]; 241 | 242 | $crate::define_extract_choice![ $name ; 243 | $( $labels ),* 244 | ]; 245 | }; 246 | 247 | ( $name:ident 248 | < $( $types:ident ),+ $(,)? > ; 249 | $( $labels:ident : $protocols:ty ),+ 250 | $(,)? 251 | ) => { 252 | $crate::define_choice_protocol![ 253 | $name < $( $types ),* > ; 254 | $( $protocols ),* 255 | ]; 256 | 257 | $crate::define_choice_labels![ 258 | $( $labels ),* 259 | ]; 260 | 261 | $crate::define_choice_enum![ $name ; 262 | $( $labels ),* 263 | ]; 264 | 265 | $crate::define_extract_choice![ $name ; 266 | $( $labels ),* 267 | ]; 268 | }; 269 | } 270 | 271 | #[macro_export] 272 | macro_rules! send_value { 273 | ($val:expr, $cont:expr) => { 274 | $crate::prelude::step( 275 | async move { $crate::prelude::send_value($val, $cont) }, 276 | ) 277 | }; 278 | } 279 | 280 | #[macro_export] 281 | macro_rules! send_value_to { 282 | ($chan:expr, $val:expr, $cont:expr) => { 283 | $crate::prelude::step(async move { 284 | $crate::prelude::send_value_to($chan, $val, $cont) 285 | }) 286 | }; 287 | } 288 | 289 | #[macro_export] 290 | macro_rules! receive_value { 291 | ( $var:ident => $body:expr ) => { 292 | $crate::prelude::receive_value ( 293 | move | $var | { 294 | $crate::prelude::step ( async move { 295 | $body 296 | }) 297 | } 298 | ) 299 | }; 300 | ( ($var:ident $( : $type:ty )?) => $body:expr ) => { 301 | $crate::prelude::receive_value ( 302 | move | $var $( : $type )* | { 303 | $crate::prelude::step ( async move { 304 | $body 305 | }) 306 | } 307 | ) 308 | } 309 | } 310 | 311 | #[macro_export] 312 | macro_rules! receive_value_from { 313 | ( $chan:expr, 314 | $var:ident => $body:expr 315 | ) => { 316 | $crate::prelude::receive_value_from ( 317 | $chan, 318 | move | $var | { 319 | $crate::prelude::step ( async move { 320 | $body 321 | }) 322 | } 323 | ) 324 | }; 325 | ( $chan:expr, 326 | ($var:ident $( : $type:ty )?) => $body:expr 327 | ) => { 328 | $crate::prelude::receive_value_from ( 329 | $chan, 330 | move | $var $( : $type )* | { 331 | $crate::prelude::step ( async move { 332 | $body 333 | }) 334 | } 335 | ) 336 | } 337 | } 338 | 339 | #[macro_export] 340 | macro_rules! choose { 341 | ($chan:expr, $label:ident, $cont:expr) => { 342 | $crate::macros::paste! { 343 | $crate::prelude::choose ( 344 | $chan, 345 | [< $label Label >], 346 | $cont 347 | ) 348 | } 349 | }; 350 | } 351 | 352 | #[macro_export] 353 | macro_rules! offer_case { 354 | ($label:ident, $cont:expr) => { 355 | $crate::macros::paste! { 356 | $crate::prelude::offer_case ( 357 | [< $label Label >], 358 | $cont 359 | ) 360 | } 361 | }; 362 | } 363 | 364 | #[macro_export] 365 | macro_rules! acquire_shared_session { 366 | ($chan:expr, $var:ident => $body:expr) => { 367 | $crate::prelude::acquire_shared_session($chan.clone(), move |$var| { 368 | $crate::prelude::step(async move { $body }) 369 | }) 370 | }; 371 | } 372 | 373 | #[macro_export] 374 | macro_rules! receive_channel { 375 | ($var:ident => $body:expr) => { 376 | $crate::prelude::receive_channel(move |$var| { 377 | $crate::prelude::step(async move { $body }) 378 | }) 379 | }; 380 | } 381 | 382 | #[macro_export] 383 | macro_rules! receive_channels { 384 | ( ( $var:ident $(,)? ) => $body:expr ) => { 385 | $crate::receive_channel!( $var => $body ) 386 | }; 387 | ( ( $var:ident, $( $vars:ident ),* $(,)? ) 388 | => $body:expr 389 | ) => { 390 | $crate::receive_channel! ( $var => { 391 | $crate::receive_channels! ( 392 | ( $( $vars ),* ) => 393 | $body 394 | ) 395 | }) 396 | }; 397 | } 398 | 399 | #[macro_export] 400 | macro_rules! receive_channel_from { 401 | ($chan:expr, $var:ident => $body:expr) => { 402 | $crate::prelude::receive_channel_from($chan, move |$var| $body) 403 | }; 404 | } 405 | 406 | #[macro_export] 407 | macro_rules! include_session { 408 | ($session:expr, $var:ident => $body:expr) => { 409 | $crate::prelude::include_session($session, move |$var| { 410 | $crate::prelude::step(async move { $body }) 411 | }) 412 | }; 413 | } 414 | 415 | #[macro_export] 416 | macro_rules! terminate { 417 | () => { 418 | $crate::prelude::terminate() 419 | }; 420 | ($cont:expr) => { 421 | $crate::prelude::terminate_async(move || async move { $cont }) 422 | }; 423 | } 424 | 425 | #[macro_export] 426 | macro_rules! wait { 427 | ($chan:expr, $cont:expr) => { 428 | $crate::prelude::wait($chan, $crate::prelude::step(async move { $cont })) 429 | }; 430 | } 431 | 432 | #[macro_export] 433 | macro_rules! wait_all { 434 | ( [ $chan:expr $(,)? ], 435 | $cont:expr 436 | ) => { 437 | $crate::prelude::wait! ( $chan, $cont ) 438 | }; 439 | ( [ $chan:expr, $( $chans:expr ),* $(,)? ], 440 | $cont:expr 441 | ) => { 442 | $crate::prelude::wait! ( $chan, 443 | $crate::prelude::wait_all! ( 444 | [ $( $chans ),* ], 445 | $cont 446 | ) 447 | ) 448 | }; 449 | } 450 | 451 | #[macro_export] 452 | macro_rules! cut { 453 | ( [ $( $labels:ty ),+ $(,)? ] ; 454 | $cont1:expr ; 455 | $var:ident => $cont2:expr 456 | ) => { 457 | < $crate::prelude::HList![ $( $labels ),* ] 458 | as $crate::prelude::Cut < _ > 459 | > :: cut ( 460 | $cont1, 461 | move | $var | { 462 | $crate::prelude::step ( async move { 463 | $cont2 464 | }) 465 | } 466 | ) 467 | } 468 | } 469 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "locked": { 5 | "lastModified": 1642700792, 6 | "narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=", 7 | "owner": "numtide", 8 | "repo": "flake-utils", 9 | "rev": "846b2ae0fc4cc943637d3d1def4454213e203cba", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "numtide", 14 | "repo": "flake-utils", 15 | "type": "github" 16 | } 17 | }, 18 | "naersk": { 19 | "inputs": { 20 | "nixpkgs": "nixpkgs" 21 | }, 22 | "locked": { 23 | "lastModified": 1639947939, 24 | "narHash": "sha256-pGsM8haJadVP80GFq4xhnSpNitYNQpaXk4cnA796Cso=", 25 | "owner": "nix-community", 26 | "repo": "naersk", 27 | "rev": "2fc8ce9d3c025d59fee349c1f80be9785049d653", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "nix-community", 32 | "repo": "naersk", 33 | "type": "github" 34 | } 35 | }, 36 | "nixpkgs": { 37 | "locked": { 38 | "lastModified": 1642762012, 39 | "narHash": "sha256-hJqPNDyooFxhGOd4mRleWl9kj1EACziLctrjneW0pbU=", 40 | "owner": "NixOS", 41 | "repo": "nixpkgs", 42 | "rev": "787ced6423cbfd130471aaf0a5e66ca3fd3e6af0", 43 | "type": "github" 44 | }, 45 | "original": { 46 | "id": "nixpkgs", 47 | "type": "indirect" 48 | } 49 | }, 50 | "nixpkgs_2": { 51 | "locked": { 52 | "lastModified": 1642762012, 53 | "narHash": "sha256-hJqPNDyooFxhGOd4mRleWl9kj1EACziLctrjneW0pbU=", 54 | "owner": "NixOS", 55 | "repo": "nixpkgs", 56 | "rev": "787ced6423cbfd130471aaf0a5e66ca3fd3e6af0", 57 | "type": "github" 58 | }, 59 | "original": { 60 | "id": "nixpkgs", 61 | "type": "indirect" 62 | } 63 | }, 64 | "root": { 65 | "inputs": { 66 | "flake-utils": "flake-utils", 67 | "naersk": "naersk", 68 | "nixpkgs": "nixpkgs_2" 69 | } 70 | } 71 | }, 72 | "root": "root", 73 | "version": 7 74 | } 75 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Session types EDSL for Rust"; 3 | 4 | inputs = { 5 | flake-utils.url = github:numtide/flake-utils; 6 | naersk.url = "github:nix-community/naersk"; 7 | }; 8 | 9 | outputs = { nixpkgs, flake-utils, naersk, ... }: 10 | flake-utils.lib.eachDefaultSystem (system: 11 | let 12 | pkgs = nixpkgs.legacyPackages."${system}"; 13 | naersk-lib = naersk.lib."${system}"; 14 | 15 | ferrite = naersk-lib.buildPackage { 16 | pname = "ferrite-session"; 17 | root = ./.; 18 | }; 19 | 20 | ferrite-demo = naersk-lib.buildPackage { 21 | pname = "ferrite-demo"; 22 | root = ./.; 23 | }; 24 | 25 | hello-app = { 26 | type = "app"; 27 | program = ferrite-demo + "/bin/hello"; 28 | }; 29 | in { 30 | packages = { inherit ferrite; }; 31 | defaultPackage = ferrite; 32 | 33 | apps = { 34 | hello = hello-app; 35 | }; 36 | 37 | defaultApp = hello-app; 38 | 39 | devShell = pkgs.mkShell { 40 | inputsFrom = [ ferrite ]; 41 | nativeBuildInputs = [ 42 | pkgs.rustc 43 | pkgs.cargo 44 | ]; 45 | }; 46 | }) 47 | ; 48 | } 49 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.61" 3 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | tab_spaces = 2 2 | max_width = 80 3 | use_field_init_shorthand = true 4 | edition = "2018" 5 | reorder_modules = true 6 | brace_style = "AlwaysNextLine" 7 | fn_args_layout = "Vertical" 8 | imports_layout = "Vertical" 9 | imports_granularity = "Crate" 10 | group_imports = "StdExternalCrate" 11 | space_before_colon = false 12 | fn_single_line = false 13 | empty_item_single_line = true 14 | format_macro_matchers = true 15 | format_macro_bodies = true 16 | reorder_impl_items = true 17 | -------------------------------------------------------------------------------- /scripts/cachix.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | nix-store -qR --include-outputs $(nix-instantiate -A project) | cachix push maybevoid 6 | --------------------------------------------------------------------------------