diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml
index b69795d..5dd20e0 100644
--- a/.gitea/workflows/build.yaml
+++ b/.gitea/workflows/build.yaml
@@ -15,4 +15,16 @@ jobs:
- name: Run clippy
run: nix build .#clippy_${{ matrix.feature }}
- name: Build & test
- run: nix build .#${{ matrix.feature }}
\ No newline at end of file
+ run: nix build .#${{ matrix.feature }}
+ docs:
+ runs-on: nix
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Build docs
+ run: nix build .#doc.doc
+ - name: (Temporary) Upload docs
+ uses: actions/upload-artifact@v2
+ with:
+ name: docs
+ path: result-doc/*
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 94ebbd6..8352a48 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -75,6 +75,28 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "async-stream"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
+dependencies = [
+ "async-stream-impl",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "backtrace"
version = "0.3.73"
@@ -142,6 +164,7 @@ dependencies = [
"serde",
"syn",
"tokio",
+ "tokio-test",
]
[[package]]
@@ -167,6 +190,12 @@ dependencies = [
"log",
]
+[[package]]
+name = "futures-core"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+
[[package]]
name = "getrandom"
version = "0.2.15"
@@ -435,6 +464,30 @@ dependencies = [
"syn",
]
+[[package]]
+name = "tokio-stream"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-test"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7"
+dependencies = [
+ "async-stream",
+ "bytes",
+ "futures-core",
+ "tokio",
+ "tokio-stream",
+]
+
[[package]]
name = "unicode-ident"
version = "1.0.12"
diff --git a/Cargo.toml b/Cargo.toml
index afee0cd..5c8ec4c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,6 +27,7 @@ log = { version = "0.4.21", optional = true }
tokio = { version = "1.38.0", features = ["sync", "rt-multi-thread", "macros", "time", "io-util", "net"] }
env_logger = "0.11.3"
log = "0.4.21"
+tokio-test = "0.4.4"
[lib]
proc-macro = true
diff --git a/README.md b/README.md
index f81d261..0ca5b6d 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,12 @@
## Stability
-Eagle is still in early development. Performance is not ideal and the interface is likely to change over time. However,
-it is in a usable state currently.
+Eagle is still in early development. Performance is not ideal, the interface is likely to change and the documentation is not final. Basic functionality is fully implemented and works as expected.
## What is Eagle?
Eagle is a library which allows you to easily build an [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) protocol.
-It uses a macro to generate the required communication code and makes adding new functions easy and quick. Eagle is designed to work specifically with `tokio` and uses `serde` for formatting data.
+It uses a macro to generate the required communication code and makes adding new functions easy and quick. Eagle is designed to work specifically with [`tokio`](https://crates.io/crates/tokio) and uses [`serde`](https://crates.io/crates/serde) for formatting data.
## Using Eagle
@@ -16,9 +15,9 @@ The way that `eagle` is designed to be used is inside a shared dependency betwee
Inside this crate, you can define your protocol as an enum:
-```rs
+```rust
use eagle::Protocol;
-use serde::{Serialize, Deserliaze};
+use serde::{Serialize, Deserialize};
#[derive(Clone, Serialize, Deserialize)]
pub struct ExampleStruct {
@@ -35,14 +34,14 @@ pub enum Example {
}
```
-Each variant describes one of the functions that the client can call, the first field on a variant represents the arguments that the client can send and the second field represents the return value. In the example above, the `addition` function would take in two `i32`s and return another `i32`. Any data passed this way must implement `Clone` as well as `serde::Serialize` and `serde::Deserialize`.
+Each variant describes one of the functions that the client can call, the first field on a variant represents the arguments that the client can send and the second field represents the return value. In the example above, the `addition` function would take in two [`i32`]s and return another [`i32`]. Any data passed this way must implement [`Clone`] as well as [`serde::Serialize`] and [`serde::Deserialize`].
+
+The [`Protocol`] macro will create a number of exports in your shared crate. You will be able to import them by name in your client and server.
Once your protocol is defined, you can implement it on your server. To do so, you must first implement a handler for your
-protocol. A handler must implement `Clone` as well as the `ServerHandler` trait for your protocol. For the above example:
-
-```rs
-use shared::ExampleServerHandler;
+protocol. A handler must implement [`Clone`] as well as the `ServerHandler` trait for your protocol. For the above example:
+```rust
struct ExampleHandler {
state: i32
}
@@ -59,14 +58,12 @@ impl ExampleServerHandler for ExampleHandler {
self.state = state;
self.state
}
-
- /* ... */
}
```
Your handler can now be used by the server. You can easily bind your server to a socket with:
-```rs
+```rust
use shared::ExampleServer;
let handler = ExampleHandler { state: 0 };
@@ -80,7 +77,7 @@ Note that bind is an asynchronous function which should never return, you must p
On the client, all you need to do is to use your protocol's `Client` to connect and you can start making requests.
-```rs
+```rust
use shared::ExampleClient;
let client = ExampleClient::connect("127.0.0.1:1234").await.unwrap();
diff --git a/flake.nix b/flake.nix
index 274dad6..ff60bf5 100644
--- a/flake.nix
+++ b/flake.nix
@@ -20,6 +20,12 @@
doCheck = true;
mode = "test";
};
+ doc = naersk-lib.buildPackage {
+ src = ./.;
+ doDoc = true;
+ mode = "test";
+ cargoDocOptions = x: x ++ ["--no-deps"];
+ };
unix = naersk-lib.buildPackage {
src = ./.;
doCheck = true;
diff --git a/src/lib.rs b/src/lib.rs
index f0a8fb8..858f204 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,5 @@
/*
-Eagle - A library for easy communication in full-stack Rust applications
+Eagle - A simple library for RPC in Rust
Copyright (c) 2024 KodiCraft
This program is free software: you can redistribute it and/or modify
@@ -15,6 +15,139 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see