bix
October 23, 2021, 6:10pm
1
I have a bit of code here that looks really WET (especially given that I kinda want to add a bunch of these in here); it seems like generics really cause problems for me like this one. Is there a general approach to make this more DRY?
let logging_on = std::env::var("BENCH_WITH_LOGGING_ON").unwrap_or_else(|_| "".to_string());
match logging_on.as_str() {
"1" | "on" | "true" | "t" | "y" | "yes" => HttpServer::new(|| {
App::new()
.wrap(TracingLogger::default())
.service(locations)
.service(health_check)
.service(health_ready)
})
.bind("127.0.0.1:8080")?
.run()
.await
.unwrap(),
_ => HttpServer::new(|| {
App::new()
.service(locations)
.service(health_check)
.service(health_ready)
})
.bind("127.0.0.1:8080")?
.run()
.await
.unwrap(),
};
It feels awful to have to capture two entire stack calls for what ought to be a couple of lines:
if env_var is set
then have the server add a tracing logger
macro_rules!
to the rescue:
macro_rules! server {
($($marker:tt)?) => {
HttpServer::new(|| {
App::new()
$(
.wrap({
// discard and return the logger
stringify!($marker);
TracingLogger::default()
})
)?
.service(locations)
.service(health_check)
.service(health_ready)
})
.bind("127.0.0.1:8080")?
.run()
.await
.unwrap()
}
}
Which turns all of your code in a simple:
match logging_on.as_str() {
"1" | "on" | "true" |
"t" | "y" | "yes"
=> server!(with_log),
_else => server!(),
};
1 Like
bix
October 23, 2021, 6:37pm
3
I hadn't thought about macros. Thanks so much!
1 Like
bix
October 23, 2021, 6:56pm
4
For reference, in case some one else stumbles over this:
fn is_true(value: &str) -> Option<bool> {
match value {
"1" | "on" | "true" | "t" | "y" | "yes" => Some(true),
"0" | "off" | "false" | "f" | "n" | "no" => Some(false),
_ => None,
}
}
macro_rules! server {
( $( $marker:expr ),* ) => {
HttpServer::new(move || {
App::new()
$(
.wrap($marker)
)*
.service(locations)
.service(health_check)
.service(health_ready)
})
.bind("127.0.0.1:8080")?
.run()
.await
.unwrap()
}
}
and now...
let with_log = std::env::var("BENCH_WITH_LOGGING_ON").unwrap_or_else(|_| "".to_string());
let with_compression = std::env::var("BENCH_WITH_COMPRESSION_ON").unwrap_or_else(|_| "".to_string());
match (with_log.as_str(), with_compression.as_str()) {
(x, y) if is_true(x) == Some(true) && is_true(y) == Some(true) => server!(TracingLogger::default(), middleware::Compress::default()),
(x, y) if is_true(x) != Some(true) && is_true(y) == Some(true) => server!(middleware::Compress::default()),
(x, y) if is_true(x) == Some(true) && is_true(y) != Some(true) => server!(TracingLogger::default()),
_else => server!(),
};
1 Like
You could simplify that a bit more if you'd like
fn is_true(value: impl AsRef<str>) -> Option<bool> {
match value.as_ref() {
"1" | "on" | "true" | "t" | "y" | "yes" => Some(true),
"0" | "off" | "false" | "f" | "n" | "no" => Some(false),
_ => None,
}
}
let with_log = std::env::var("BENCH_WITH_LOGGING_ON").unwrap_or_default();
let with_compression = std::env::var("BENCH_WITH_COMPRESSION_ON").unwrap_or_default();
match (is_true(&with_log), is_true(&with_compression)) {
(Some(true), Some(true)) => server!(TracingLogger::default(), middleware::Compress::default()),
(Some(false), Some(true)) => server!(middleware::Compress::default()),
(Some(true), Some(false)) => server!(TracingLogger::default())
_else => server!(),
};
2 Likes
system
Closed
January 21, 2022, 10:54pm
7
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.