···11+// This file is part of Windmark <https://github.com/gemrest/windmark>.
22+//
33+// This program is free software: you can redistribute it and/or modify
44+// it under the terms of the GNU General Public License as published by
55+// the Free Software Foundation, version 3.
66+//
77+// This program is distributed in the hope that it will be useful, but
88+// WITHOUT ANY WARRANTY; without even the implied warranty of
99+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+// General Public License for more details.
1111+//
1212+// You should have received a copy of the GNU General Public License
1313+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1414+//
1515+// Copyright (C) 2022-2023 Fuwn <contact@fuwn.me>
1616+// SPDX-License-Identifier: GPL-3.0-only
1717+1818+//! `cargo run --example struct_router`
1919+2020+use rossweisse::route;
2121+2222+#[rossweisse::router]
2323+struct Router {
2424+ _phantom: (),
2525+}
2626+2727+#[rossweisse::router]
2828+impl Router {
2929+ #[route]
3030+ pub fn index(
3131+ _context: windmark::context::RouteContext,
3232+ ) -> windmark::Response {
3333+ windmark::Response::success("Hello, World!")
3434+ }
3535+}
3636+3737+#[windmark::main]
3838+async fn main() -> Result<(), Box<dyn std::error::Error>> {
3939+ {
4040+ let mut router = Router::new();
4141+4242+ router.router().set_private_key_file("windmark_private.pem");
4343+ router.router().set_certificate_file("windmark_public.pem");
4444+4545+ router
4646+ }
4747+ .run()
4848+ .await
4949+}
+16
rossweisse/Cargo.toml
···11+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
22+33+[package]
44+name = "rossweisse"
55+version = "0.0.0"
66+authors = ["Fuwn <contact@fuwn.me>"]
77+edition = "2021"
88+license = "GPL-3.0-only"
99+1010+[lib]
1111+proc-macro = true
1212+1313+[dependencies]
1414+quote = "1.0.26" # Quasi-quoting
1515+syn = "2.0.15" # Source Code Parsing
1616+proc-macro2 = "1.0.56" # `proc-macro` Wrapper
+22
rossweisse/src/implementations.rs
···11+// This file is part of Windmark <https://github.com/gemrest/windmark>.
22+//
33+// This program is free software: you can redistribute it and/or modify
44+// it under the terms of the GNU General Public License as published by
55+// the Free Software Foundation, version 3.
66+//
77+// This program is distributed in the hope that it will be useful, but
88+// WITHOUT ANY WARRANTY; without even the implied warranty of
99+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+// General Public License for more details.
1111+//
1212+// You should have received a copy of the GNU General Public License
1313+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1414+//
1515+// Copyright (C) 2022-2023 Fuwn <contact@fuwn.me>
1616+// SPDX-License-Identifier: GPL-3.0-only
1717+1818+mod route;
1919+mod router;
2020+2121+pub use route::route;
2222+pub use router::{fields, methods};
+22
rossweisse/src/implementations/route.rs
···11+// This file is part of Windmark <https://github.com/gemrest/windmark>.
22+//
33+// This program is free software: you can redistribute it and/or modify
44+// it under the terms of the GNU General Public License as published by
55+// the Free Software Foundation, version 3.
66+//
77+// This program is distributed in the hope that it will be useful, but
88+// WITHOUT ANY WARRANTY; without even the implied warranty of
99+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+// General Public License for more details.
1111+//
1212+// You should have received a copy of the GNU General Public License
1313+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1414+//
1515+// Copyright (C) 2022-2023 Fuwn <contact@fuwn.me>
1616+// SPDX-License-Identifier: GPL-3.0-only
1717+1818+use proc_macro::TokenStream;
1919+2020+pub fn route(_arguments: TokenStream, item: syn::ItemFn) -> TokenStream {
2121+ quote::quote! { #item }.into()
2222+}
+23
rossweisse/src/implementations/router.rs
···11+// This file is part of Windmark <https://github.com/gemrest/windmark>.
22+//
33+// This program is free software: you can redistribute it and/or modify
44+// it under the terms of the GNU General Public License as published by
55+// the Free Software Foundation, version 3.
66+//
77+// This program is distributed in the hope that it will be useful, but
88+// WITHOUT ANY WARRANTY; without even the implied warranty of
99+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+// General Public License for more details.
1111+//
1212+// You should have received a copy of the GNU General Public License
1313+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1414+//
1515+// Copyright (C) 2022-2023 Fuwn <contact@fuwn.me>
1616+// SPDX-License-Identifier: GPL-3.0-only
1717+1818+mod fields;
1919+mod methods;
2020+mod parser;
2121+2222+pub use fields::fields;
2323+pub use methods::methods;
+86
rossweisse/src/implementations/router/fields.rs
···11+// This file is part of Windmark <https://github.com/gemrest/windmark>.
22+//
33+// This program is free software: you can redistribute it and/or modify
44+// it under the terms of the GNU General Public License as published by
55+// the Free Software Foundation, version 3.
66+//
77+// This program is distributed in the hope that it will be useful, but
88+// WITHOUT ANY WARRANTY; without even the implied warranty of
99+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+// General Public License for more details.
1111+//
1212+// You should have received a copy of the GNU General Public License
1313+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1414+//
1515+// Copyright (C) 2022-2023 Fuwn <contact@fuwn.me>
1616+// SPDX-License-Identifier: GPL-3.0-only
1717+1818+use proc_macro::TokenStream;
1919+use quote::quote;
2020+use syn::parse_macro_input;
2121+2222+pub fn fields(arguments: TokenStream, item: syn::ItemStruct) -> TokenStream {
2323+ let field_initializers =
2424+ parse_macro_input!(arguments as super::parser::FieldInitializers);
2525+ let router_identifier = item.ident;
2626+ let named_fields = match item.fields {
2727+ syn::Fields::Named(fields) => fields,
2828+ _ =>
2929+ panic!(
3030+ "`#[rossweisse::router]` can only be used on `struct`s with named \
3131+ fields"
3232+ ),
3333+ };
3434+ let mut default_expressions = vec![];
3535+ let new_method_fields = named_fields.named.iter().map(|field| {
3636+ let name = &field.ident;
3737+ let initialiser = field_initializers
3838+ .0
3939+ .iter()
4040+ .find(|initialiser| initialiser.ident == name.clone().unwrap())
4141+ .map(|initialiser| &initialiser.expr)
4242+ .unwrap_or_else(|| {
4343+ default_expressions.push({
4444+ let default_expression: syn::Expr =
4545+ syn::parse_quote! { ::std::default::Default::default() };
4646+4747+ default_expression
4848+ });
4949+5050+ default_expressions.last().unwrap()
5151+ });
5252+5353+ quote! {
5454+ #name: #initialiser,
5555+ }
5656+ });
5757+ let new_methods = quote! {
5858+ fn _new() -> Self {
5959+ Self {
6060+ #(#new_method_fields)*
6161+ router: ::windmark::Router::new(),
6262+ }
6363+ }
6464+6565+ pub async fn run(&mut self) -> Result<(), Box<dyn std::error::Error>> {
6666+ self.router.run().await
6767+ }
6868+6969+ pub fn router(&mut self) -> &mut ::windmark::Router {
7070+ &mut self.router
7171+ }
7272+ };
7373+ let output_fields = named_fields.named;
7474+ let output = quote! {
7575+ struct #router_identifier {
7676+ #output_fields
7777+ router: ::windmark::Router,
7878+ }
7979+8080+ impl #router_identifier {
8181+ #new_methods
8282+ }
8383+ };
8484+8585+ output.into()
8686+}
+66
rossweisse/src/implementations/router/methods.rs
···11+// This file is part of Windmark <https://github.com/gemrest/windmark>.
22+//
33+// This program is free software: you can redistribute it and/or modify
44+// it under the terms of the GNU General Public License as published by
55+// the Free Software Foundation, version 3.
66+//
77+// This program is distributed in the hope that it will be useful, but
88+// WITHOUT ANY WARRANTY; without even the implied warranty of
99+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+// General Public License for more details.
1111+//
1212+// You should have received a copy of the GNU General Public License
1313+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1414+//
1515+// Copyright (C) 2022-2023 Fuwn <contact@fuwn.me>
1616+// SPDX-License-Identifier: GPL-3.0-only
1717+1818+use proc_macro::TokenStream;
1919+2020+pub fn methods(_arguments: TokenStream, item: syn::ItemImpl) -> TokenStream {
2121+ let routes = item
2222+ .items
2323+ .iter()
2424+ .filter_map(|item| {
2525+ if let syn::ImplItem::Fn(method) = item {
2626+ if method
2727+ .attrs
2828+ .iter()
2929+ .any(|attribute| attribute.path().is_ident("route"))
3030+ {
3131+ Some(method.sig.ident.clone())
3232+ } else {
3333+ None
3434+ }
3535+ } else {
3636+ None
3737+ }
3838+ })
3939+ .collect::<Vec<_>>();
4040+ let (implementation_generics, type_generics, where_clause) =
4141+ item.generics.split_for_impl();
4242+ let name = &item.self_ty;
4343+ let route_paths = routes
4444+ .iter()
4545+ .map(|route| format!("/{}", route))
4646+ .collect::<Vec<_>>();
4747+4848+ quote::quote! {
4949+ #item
5050+5151+ impl #implementation_generics #name #type_generics #where_clause {
5252+ pub fn new() -> Self {
5353+ let mut router = Self::_new();
5454+5555+ #(
5656+ router.router.mount(#route_paths, |context| {
5757+ Self::#routes(context)
5858+ });
5959+ )*
6060+6161+ router
6262+ }
6363+ }
6464+ }
6565+ .into()
6666+}
+21
rossweisse/src/implementations/router/parser.rs
···11+// This file is part of Windmark <https://github.com/gemrest/windmark>.
22+//
33+// This program is free software: you can redistribute it and/or modify
44+// it under the terms of the GNU General Public License as published by
55+// the Free Software Foundation, version 3.
66+//
77+// This program is distributed in the hope that it will be useful, but
88+// WITHOUT ANY WARRANTY; without even the implied warranty of
99+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+// General Public License for more details.
1111+//
1212+// You should have received a copy of the GNU General Public License
1313+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1414+//
1515+// Copyright (C) 2022-2023 Fuwn <contact@fuwn.me>
1616+// SPDX-License-Identifier: GPL-3.0-only
1717+1818+mod field_initializer;
1919+mod field_initializers;
2020+2121+pub use field_initializers::FieldInitializers;
···11+// This file is part of Windmark <https://github.com/gemrest/windmark>.
22+//
33+// This program is free software: you can redistribute it and/or modify
44+// it under the terms of the GNU General Public License as published by
55+// the Free Software Foundation, version 3.
66+//
77+// This program is distributed in the hope that it will be useful, but
88+// WITHOUT ANY WARRANTY; without even the implied warranty of
99+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+// General Public License for more details.
1111+//
1212+// You should have received a copy of the GNU General Public License
1313+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1414+//
1515+// Copyright (C) 2022-2023 Fuwn <contact@fuwn.me>
1616+// SPDX-License-Identifier: GPL-3.0-only
1717+1818+use syn::parse;
1919+2020+pub struct FieldInitializer {
2121+ pub ident: syn::Ident,
2222+ #[allow(unused)]
2323+ eq_token: syn::Token![=],
2424+ pub expr: syn::Expr,
2525+}
2626+2727+impl parse::Parse for FieldInitializer {
2828+ fn parse(input: parse::ParseStream<'_>) -> syn::Result<Self> {
2929+ let ident = input.parse()?;
3030+ let eq_token = input.parse()?;
3131+ let expr = input.parse()?;
3232+3333+ Ok(Self {
3434+ ident,
3535+ eq_token,
3636+ expr,
3737+ })
3838+ }
3939+}
···11+// This file is part of Windmark <https://github.com/gemrest/windmark>.
22+//
33+// This program is free software: you can redistribute it and/or modify
44+// it under the terms of the GNU General Public License as published by
55+// the Free Software Foundation, version 3.
66+//
77+// This program is distributed in the hope that it will be useful, but
88+// WITHOUT ANY WARRANTY; without even the implied warranty of
99+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+// General Public License for more details.
1111+//
1212+// You should have received a copy of the GNU General Public License
1313+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1414+//
1515+// Copyright (C) 2022-2023 Fuwn <contact@fuwn.me>
1616+// SPDX-License-Identifier: GPL-3.0-only
1717+1818+use syn::parse;
1919+2020+use super::field_initializer::FieldInitializer;
2121+2222+pub struct FieldInitializers(pub Vec<FieldInitializer>);
2323+2424+impl parse::Parse for FieldInitializers {
2525+ fn parse(input: parse::ParseStream<'_>) -> syn::Result<Self> {
2626+ Ok(Self(syn::punctuated::Punctuated::<FieldInitializer, syn::Token![,]>::parse_terminated(input)?.into_iter().collect()))
2727+ }
2828+}
+91
rossweisse/src/lib.rs
···11+// This file is part of Windmark <https://github.com/gemrest/windmark>.
22+//
33+// This program is free software: you can redistribute it and/or modify
44+// it under the terms of the GNU General Public License as published by
55+// the Free Software Foundation, version 3.
66+//
77+// This program is distributed in the hope that it will be useful, but
88+// WITHOUT ANY WARRANTY; without even the implied warranty of
99+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+// General Public License for more details.
1111+//
1212+// You should have received a copy of the GNU General Public License
1313+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1414+//
1515+// Copyright (C) 2022-2023 Fuwn <contact@fuwn.me>
1616+// SPDX-License-Identifier: GPL-3.0-only
1717+1818+#![deny(
1919+ clippy::all,
2020+ clippy::nursery,
2121+ clippy::pedantic,
2222+ future_incompatible,
2323+ nonstandard_style,
2424+ rust_2018_idioms,
2525+ unsafe_code,
2626+ unused,
2727+ warnings
2828+)]
2929+#![recursion_limit = "128"]
3030+3131+mod implementations;
3232+3333+use proc_macro::TokenStream;
3434+use syn::Item;
3535+3636+/// Marks a `struct` as a router or marks an `impl` block as a router
3737+/// implementation
3838+///
3939+/// # Examples
4040+///
4141+/// ```rust
4242+/// #[rossweisse::router]
4343+/// struct Router {
4444+/// _phantom: (),
4545+/// }
4646+///
4747+/// #[rossweisse::router]
4848+/// impl Router {
4949+/// #[route]
5050+/// pub fn index(
5151+/// _context: windmark::context::RouteContext,
5252+/// ) -> windmark::Response {
5353+/// windmark::Response::success("Hello, World!")
5454+/// }
5555+/// }
5656+/// ```
5757+#[proc_macro_attribute]
5858+pub fn router(arguments: TokenStream, item: TokenStream) -> TokenStream {
5959+ let output = match syn::parse::<Item>(item.clone()) {
6060+ Ok(Item::Struct(item)) => implementations::fields(arguments, item),
6161+ Ok(Item::Impl(item)) => implementations::methods(arguments, item),
6262+ _ => panic!("`#[rossweisse::router]` can only be used on `struct`s"),
6363+ };
6464+6565+ output.into()
6666+}
6767+6868+/// Marks a method of a router implementation as a route to mount
6969+///
7070+/// # Examples
7171+///
7272+/// ```rust
7373+/// #[rossweisse::router]
7474+/// impl Router {
7575+/// #[route]
7676+/// pub fn index(
7777+/// _context: windmark::context::RouteContext,
7878+/// ) -> windmark::Response {
7979+/// windmark::Response::success("Hello, World!")
8080+/// }
8181+/// }
8282+/// ```
8383+#[proc_macro_attribute]
8484+pub fn route(arguments: TokenStream, item: TokenStream) -> TokenStream {
8585+ let output = match syn::parse::<Item>(item.clone()) {
8686+ Ok(Item::Fn(item)) => implementations::route(arguments, item),
8787+ _ => panic!("`#[rossweisse::route]` can only be used on `fn`s"),
8888+ };
8989+9090+ output.into()
9191+}