From 695f450c64669c6935e73c942bd4ef0ba4a0b725 Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Tue, 13 Jun 2023 15:56:15 -0700 Subject: [PATCH] Use proc macro for optional optional user. --- Cargo.lock | 18 ++--- Cargo.toml | 2 +- maybe_optional_user/src/lib.rs | 34 --------- .../Cargo.lock | 0 .../Cargo.toml | 2 +- optional_optional_user/src/lib.rs | 40 +++++++++++ src/login.rs | 6 +- src/signup.rs | 4 +- src/templates.rs | 72 +++++++------------ src/users.rs | 1 - src/watches/templates.rs | 12 ++-- templates/base.html | 4 +- .../{header.html => header_with_user.html} | 2 +- templates/login_get.html | 2 + templates/logout_get.html | 2 + templates/logout_post.html | 2 + templates/signup.html | 2 +- templates/signup_success.html | 3 +- 18 files changed, 98 insertions(+), 110 deletions(-) delete mode 100644 maybe_optional_user/src/lib.rs rename {maybe_optional_user => optional_optional_user}/Cargo.lock (100%) rename {maybe_optional_user => optional_optional_user}/Cargo.toml (78%) create mode 100644 optional_optional_user/src/lib.rs rename templates/{header.html => header_with_user.html} (91%) diff --git a/Cargo.lock b/Cargo.lock index 45083fe..19f09b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1066,14 +1066,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" -[[package]] -name = "maybe_optional_user" -version = "0.1.0" -dependencies = [ - "quote", - "syn 2.0.18", -] - [[package]] name = "memchr" version = "2.5.0" @@ -1174,6 +1166,14 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "optional_optional_user" +version = "0.1.0" +dependencies = [ + "quote", + "syn 2.0.18", +] + [[package]] name = "overload" version = "0.1.1" @@ -2381,7 +2381,7 @@ dependencies = [ "axum-macros", "axum-test", "justerror", - "maybe_optional_user", + "optional_optional_user", "password-hash", "rand_core", "serde", diff --git a/Cargo.toml b/Cargo.toml index 7327a11..c97229e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ unicode-segmentation = "1" async-session = "3" # proc macros: -maybe_optional_user = {path = "maybe_optional_user"} +optional_optional_user = {path = "optional_optional_user"} [dev-dependencies] axum-test = "9.0.0" diff --git a/maybe_optional_user/src/lib.rs b/maybe_optional_user/src/lib.rs deleted file mode 100644 index fc767b6..0000000 --- a/maybe_optional_user/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, ItemStruct}; - -#[proc_macro_derive(ImplMaybeOptionalUser)] -pub fn derive_maybe_optional_user(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as ItemStruct); - - let name = &input.ident; - let mut has_opt_user = false; - input.fields.iter().inspect(|f| { - if let Some(ident) = f.ident.clone() { - match &f.ty { - syn::Type::Path(path) - if !path.path.segments.is_empty() - && path.path.segments.first().unwrap().ident == "Option" => - { - has_opt_user = true && ident == "user"; - } - _ => {} - } - } - }); - - let output = quote! { - impl crate::templates::MaybeOptionalUser for #name { - fn has_optional_user() -> bool { - #has_opt_user - } - } - }; - - TokenStream::from(output) -} diff --git a/maybe_optional_user/Cargo.lock b/optional_optional_user/Cargo.lock similarity index 100% rename from maybe_optional_user/Cargo.lock rename to optional_optional_user/Cargo.lock diff --git a/maybe_optional_user/Cargo.toml b/optional_optional_user/Cargo.toml similarity index 78% rename from maybe_optional_user/Cargo.toml rename to optional_optional_user/Cargo.toml index b25cdff..091ebcc 100644 --- a/maybe_optional_user/Cargo.toml +++ b/optional_optional_user/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "maybe_optional_user" +name = "optional_optional_user" version = "0.1.0" edition = "2021" diff --git a/optional_optional_user/src/lib.rs b/optional_optional_user/src/lib.rs new file mode 100644 index 0000000..bc8c2f5 --- /dev/null +++ b/optional_optional_user/src/lib.rs @@ -0,0 +1,40 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, ItemStruct}; + +#[proc_macro_derive(OptionalOptionalUser)] +pub fn derive_optional_optional_user(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as ItemStruct); + + let name = &input.ident; + let has_user = input + .fields + .iter() + .find(|f| { + if let Some(ident) = f.ident.clone() { + ident == "user" + } else { + false + } + }) + .is_some(); + + let has_option = if has_user { + quote!( + ::std::any::TypeId::of::<::std::option::Option>() == self.user.type_id() + ) + } else { + quote!(false) + }; + + let output = quote!( + impl crate::templates::OptionalOptionalUser for #name { + fn has_optional_user(&self) -> bool { + use ::std::any::Any; + #has_user && #has_option + } + } + ); + + TokenStream::from(output) +} diff --git a/src/login.rs b/src/login.rs index 2060cc2..a2dea90 100644 --- a/src/login.rs +++ b/src/login.rs @@ -165,7 +165,7 @@ mod test { let s = server().await; let resp = s.get("/logout").await; let body = std::str::from_utf8(resp.bytes()).unwrap().to_string(); - assert_eq!(body, LogoutGet::default().to_string()); + assert_eq!(body, LogoutGet.to_string()); } #[tokio::test] @@ -174,7 +174,7 @@ mod test { let resp = s.post("/logout").await; resp.assert_status_ok(); let body = std::str::from_utf8(resp.bytes()).unwrap(); - let default = LogoutPost::default().to_string(); + let default = LogoutPost.to_string(); assert_eq!(body, &default); } @@ -205,7 +205,7 @@ mod test { let resp = s.post("/logout").await; let body = std::str::from_utf8(resp.bytes()).unwrap(); - let default = LogoutPost::default().to_string(); + let default = LogoutPost.to_string(); assert_eq!(body, &default); } } diff --git a/src/signup.rs b/src/signup.rs index 6365ff8..171a643 100644 --- a/src/signup.rs +++ b/src/signup.rs @@ -122,7 +122,7 @@ pub async fn handle_signup_success( .unwrap_or_default() }; - let mut resp = CreateUserSuccess { user: user.clone() }.into_response(); + let mut resp = CreateUserSuccess(user.clone()).into_response(); if user.username.is_empty() || id.is_empty() { // redirect to front page if we got here without a valid witch ID @@ -260,7 +260,7 @@ mod test { let resp = server.get(&path).expect_success().await; let body = std::str::from_utf8(resp.bytes()).unwrap(); - let expected = CreateUserSuccess { user }.to_string(); + let expected = CreateUserSuccess(user).to_string(); assert_eq!(&expected, body); } diff --git a/src/templates.rs b/src/templates.rs index 02ed349..6128caf 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -1,15 +1,14 @@ use askama::Template; +use optional_optional_user::OptionalOptionalUser; use serde::{Deserialize, Serialize}; use crate::User; -pub trait MaybeOptionalUser { - fn has_optional_user() -> bool { - false - } +pub trait OptionalOptionalUser { + fn has_optional_user(&self) -> bool; } -#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser)] #[template(path = "signup.html")] pub struct CreateUser { pub username: String, @@ -17,24 +16,13 @@ pub struct CreateUser { pub email: Option, pub password: String, pub pw_verify: String, - user: Option, -} -impl MaybeOptionalUser for CreateUser { - fn has_optional_user() -> bool { - true - } } -#[derive(Debug, Clone, Template, Default, Deserialize, Serialize, PartialEq, Eq)] +#[derive( + Debug, Clone, Template, Default, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser, +)] #[template(path = "signup_success.html")] -pub struct CreateUserSuccess { - pub user: User, -} -impl MaybeOptionalUser for CreateUserSuccess { - fn has_optional_user() -> bool { - false - } -} +pub struct CreateUserSuccess(pub User); #[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq)] #[template(path = "login_post.html")] @@ -42,49 +30,39 @@ pub struct LoginPost { pub username: String, pub password: String, } -impl MaybeOptionalUser for LoginPost { - fn has_optional_user() -> bool { - false - } -} -#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser)] #[template(path = "login_get.html")] pub struct LoginGet { pub username: String, pub password: String, } -impl MaybeOptionalUser for LoginGet { - fn has_optional_user() -> bool { - false - } -} -#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser)] #[template(path = "logout_get.html")] pub struct LogoutGet; -impl MaybeOptionalUser for LogoutGet { - fn has_optional_user() -> bool { - false - } -} -#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser)] #[template(path = "logout_post.html")] pub struct LogoutPost; -impl MaybeOptionalUser for LogoutPost { - fn has_optional_user() -> bool { - false - } -} -#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser)] #[template(path = "index.html")] pub struct MainPage { pub user: Option, } -impl MaybeOptionalUser for MainPage { - fn has_optional_user() -> bool { - true + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn main_page_has_optional_user() { + assert!(MainPage::default().has_optional_user()); + } + + #[test] + fn signup_success_has_no_optional_user() { + assert!(!CreateUserSuccess::default().has_optional_user()); } } diff --git a/src/users.rs b/src/users.rs index 209ef13..433130c 100644 --- a/src/users.rs +++ b/src/users.rs @@ -1,5 +1,4 @@ use std::{ - any::Any, fmt::{Debug, Display}, time::{SystemTime, UNIX_EPOCH}, }; diff --git a/src/watches/templates.rs b/src/watches/templates.rs index f27e72f..10a62fb 100644 --- a/src/watches/templates.rs +++ b/src/watches/templates.rs @@ -1,18 +1,16 @@ use askama::Template; +use optional_optional_user::OptionalOptionalUser; use serde::{Deserialize, Serialize}; -use crate::{User, Watch}; +use crate::{templates::OptionalOptionalUser, User, Watch}; -#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser)] #[template(path = "get_watches.html")] pub struct GetWatches { pub watches: Vec, pub user: Option, } -#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser)] #[template(path = "get_search_watches.html")] -pub struct GetSearchWatches { - pub watches: Vec, - pub user: Option, -} +pub struct GetSearchWatches {} diff --git a/templates/base.html b/templates/base.html index 6875281..76aa293 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,11 +4,11 @@ {% block title %}{{ title }} - Witch Watch{% endblock %} - {% block head %}{% include "header.html" %}{% endblock %} + {% block head %}{% endblock %}
{% block content %}{% endblock %} diff --git a/templates/header.html b/templates/header_with_user.html similarity index 91% rename from templates/header.html rename to templates/header_with_user.html index e2e9788..e3e2fc7 100644 --- a/templates/header.html +++ b/templates/header_with_user.html @@ -1,4 +1,4 @@ -{% if Self::has_optional_user() %} +{% if self.has_optional_user() %} {% match user %} {% when Some with (usr) %} diff --git a/templates/login_get.html b/templates/login_get.html index ea7a1a7..40ee3e3 100644 --- a/templates/login_get.html +++ b/templates/login_get.html @@ -2,6 +2,8 @@ {% block title %}Login to Witch Watch, Bish{% endblock %} +{% block header %}{% endblock %} + {% block content %}

diff --git a/templates/logout_get.html b/templates/logout_get.html index 4ed382a..d54ca87 100644 --- a/templates/logout_get.html +++ b/templates/logout_get.html @@ -2,6 +2,8 @@ {% block title %}Logout of Witch Watch, Bish{% endblock %} +{% block header %}{% endblock %} + {% block content %}

diff --git a/templates/logout_post.html b/templates/logout_post.html index 69dffba..2e176bd 100644 --- a/templates/logout_post.html +++ b/templates/logout_post.html @@ -2,6 +2,8 @@ {% block title %}Thanks for Signing Up for Witch Watch, Bish{% endblock %} +{% block header %}{% endblock %} + {% block content %}

Goodbye

diff --git a/templates/signup.html b/templates/signup.html index 6de857d..e4aeb0f 100644 --- a/templates/signup.html +++ b/templates/signup.html @@ -2,7 +2,7 @@ {% block title %}Sign Up for Witch Watch, Bish{% endblock %} -{% block header %}{% endblock %} +{% block header %} {% endblock %} {% block content %} diff --git a/templates/signup_success.html b/templates/signup_success.html index 3bd41da..6d6bd39 100644 --- a/templates/signup_success.html +++ b/templates/signup_success.html @@ -3,11 +3,12 @@ {% block title %}Thanks for Signing Up for Witch Watch, Bish{% endblock %} {% block content %} +{% block header %}{% endblock %}

You did it!

-{{ self.user }} +{{ self.0 }}