1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! A library for type-safe interprocess communication.
//!
//! # Usage
//! Define the input and output of a wired connection:
//!
//! ```
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Serialize, Deserialize)]
//! pub struct Credentials {
//! username: String,
//! password: String,
//! }
//!
//! #[derive(Serialize, Deserialize)]
//! pub enum Authentication {
//! Success { token: String },
//! Error { description: String },
//! }
//! ```
//!
//! Create a [`Plug`] for this specific action:
//!
//! ```
//! # use serde::{Deserialize, Serialize};
//! #
//! # #[derive(Serialize, Deserialize)]
//! # pub struct Credentials {
//! # username: String,
//! # password: String,
//! # }
//! #
//! # #[derive(Serialize, Deserialize)]
//! # pub enum Authentication {
//! # Success { token: String },
//! # Error { description: String },
//! # }
//! use plug::Plug;
//!
//! pub const LOG_IN: Plug<Credentials, Authentication> = Plug::new("log_in");
//! ```
//!
//! Connect the [`Plug`] to the server leveraging type-safety:
//!
//! ```
//! # use serde::{Deserialize, Serialize};
//! #
//! # #[derive(Serialize, Deserialize)]
//! # pub struct Credentials {
//! # username: String,
//! # password: String,
//! # }
//! #
//! # #[derive(Serialize, Deserialize)]
//! # pub enum Authentication {
//! # Success { token: String },
//! # Error { description: String },
//! # }
//! # use plug::Plug;
//! #
//! # pub const LOG_IN: Plug<Credentials, Authentication> = Plug::new("log_in");
//! #
//! use std::io;
//!
//! async fn log_in(credentials: Credentials) -> io::Result<Authentication> {
//! let mut connection = LOG_IN.connect("127.0.0.1:1234").await?;
//!
//! connection.write(credentials).await?;
//! connection.read().await
//! }
//! ```
//!
//! Implement the server by gathering all the [`Plug`] definitions in a [`Strip`]:
//!
//! ```
//! # use serde::{Deserialize, Serialize};
//! #
//! # #[derive(Serialize, Deserialize)]
//! # pub struct Credentials {
//! # username: String,
//! # password: String,
//! # }
//! #
//! # #[derive(Serialize, Deserialize)]
//! # pub enum Authentication {
//! # Success { token: String },
//! # Error { description: String },
//! # }
//! # use plug::Plug;
//! #
//! # pub const LOG_IN: Plug<Credentials, Authentication> = Plug::new("log_in");
//! #
//! use plug::{Connection, Strip};
//!
//! use std::io;
//! use tokio::net;
//! use tokio::task;
//!
//! async fn run_server() -> io::Result<()> {
//! let strip = Strip::new().plug(LOG_IN, log_in);
//! let server = net::TcpListener::bind("127.0.0.1:1234").await?;
//!
//! loop {
//! let Ok((client, _address)) = server.accept().await else {
//! continue;
//! };
//!
//! let _ = strip.attach(client).await;
//! }
//! }
//!
//! async fn log_in(mut connection: Connection<Authentication, Credentials>) -> io::Result<()> {
//! let credentials = connection.read().await?;
//!
//! let result = if credentials.username == "admin" && credentials.password == "1234" {
//! Authentication::Success { token: "verysecure".to_owned() }
//! } else {
//! Authentication::Error { description: "Invalid credentials!".to_owned() }
//! };
//!
//! connection.write(result).await
//! }
//! ```
pub use Connection;
pub use Plug;
pub use Strip;
pub use Infallible as Never;