[dependencies]
serde = { version = "1.0", features = ["derive"] }
+axum-rs = { version = "0.2.8", optional = true, package = "axum" }
+hyper = { version = "0.14.13", features = ["full"], optional = true }
+tokio = { version = "1.12.0", features = ["full"], optional = true }
+tower = { version = "0.4.9", optional = true}
+actix-web = { version = "1", optional = true}
-[target.'cfg(axum)'.dependencies]
-axum = "0.2.8"
-hyper = { version = "0.14.13", features = ["full"] }
-tokio = { version = "1.12.0", features = ["full"] }
-tower = "0.4.9"
-
-[target.'cfg(actix)'.dependencies]
-actix-web = "1"
+[features]
+axum = ["axum-rs", "hyper", "tokio", "tower"]
+actix = ["actix-web"]
# GCD Calculator using Actix Web OR axum
-Was built as a learning exercise to create small web apps from different web framework in the same module thanks to the `cfg` macro.
+Was built as a learning exercise to create small web apps from different web framework in the same module thanks to Cargo "features".
Dependencies are also framework specific.
## Usage
-Run in localhost using:
+In order to run this, you need to append the `--features` flag
```
-RUSTFLAGS="--cfg=<actix|axum>" cargo run
+# With axum
+cargo run --features axum
+
+# With actix
+cargo run --features actix
```
+You cannot run both at the same time.
## Downsides
-You have to prepend the `RUSTFLAGS` env anytime.
-Using neovim and rust-analyzer, linting is disabled and it becomes a pain to debug.
+Using neovim and rust-analyzer, linting is capricious and it becomes a pain to debug.
+A workaround is to add the `default` feature in your Cargo.toml. It will lint the code marked as default.
## Credits
The gcd and actix specific functions are based on *Programming Rust, 2nd Edition* by Jim Blandy, Jason Orendorff, Leonora F.S. Tindall
-#[cfg(axum)]
-use axum::{extract::Form, handler::get, response::Html, Router};
-#[cfg(axum)]
+#[cfg(all(feature = "axum", feature = "actix"))]
+compile_error!("feature \"axum\" and feature \"actix\" cannot be enabled at the same time");
+
+#[cfg(feature = "axum")]
+use axum_rs::{
+ extract::Form,
+ handler::{get, post},
+ response::Html,
+ Router,
+};
+#[cfg(feature = "axum")]
use hyper::StatusCode;
-#[cfg(axum)]
+#[cfg(feature = "axum")]
use std::net::SocketAddr;
-#[cfg(actix)]
+#[cfg(feature = "actix")]
use actix_web::{web, App, HttpResponse, HttpServer};
use serde::Deserialize;
use std::fmt;
+
#[derive(Deserialize, Debug)]
struct GcdParameters {
n: u64,
m: u64,
}
-#[cfg(axum)]
impl GcdParameters {
fn gcd(&self) -> u64 {
assert!(self.n != 0 && self.m != 0);
)
}
}
+
+#[cfg(feature = "axum")]
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/gcd", post(post_gcd));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- axum::Server::bind(&addr)
+ axum_rs::Server::bind(&addr)
.serve(app.into_make_service())
.await
.expect("error running server");
}
-#[cfg(actix)]
+#[cfg(feature = "actix")]
fn main() {
let server = HttpServer::new(|| {
App::new()
.route("/", web::get().to(get_index))
.route("/gcd", web::post().to(post_gcd))
});
- println!("Serving on http://localhost:3000...");
server
.bind("127.0.0.1:3000")
.expect("error binding server to address")
.expect("error running server");
}
-#[cfg(axum)]
+#[cfg(feature = "axum")]
async fn get_index() -> Html<&'static str> {
Html(INDEX_HTML)
}
-#[cfg(actix)]
+#[cfg(feature = "actix")]
fn get_index() -> HttpResponse {
HttpResponse::Ok()
.content_type("text/html")
.body(INDEX_HTML)
}
-#[cfg(axum)]
+#[cfg(feature = "axum")]
async fn post_gcd(
Form(input): Form<GcdParameters>,
) -> Result<Html<String>, (StatusCode, &'static str)> {
Ok(Html(input.to_string()))
}
-#[cfg(actix)]
-fn post_gcd(form: web::Form<GcdParameters>) -> HttpResponse {
- if form.n == 0 || form.m == 0 {
+#[cfg(feature = "actix")]
fn post_gcd(input: web::Form<GcdParameters>) -> HttpResponse {
if input.n == 0 || input.m == 0 {
return HttpResponse::BadRequest()