From a8a899a61e7c1386e2eb0fa8e06dd276e3c578c2 Mon Sep 17 00:00:00 2001 From: naskya <m@naskya.net> Date: Wed, 17 Jul 2024 08:26:46 +0900 Subject: [PATCH] chore (backend-rs, macro-rs): generate document from error messages --- packages/backend-rs/src/database/cache.rs | 2 +- packages/backend-rs/src/database/redis.rs | 2 +- .../src/federation/internal_actor/cache.rs | 2 +- .../src/federation/nodeinfo/fetch.rs | 2 +- .../src/federation/nodeinfo/generate.rs | 2 +- packages/backend-rs/src/misc/convert_host.rs | 2 +- .../backend-rs/src/misc/get_image_size.rs | 2 +- .../backend-rs/src/misc/latest_version.rs | 2 +- packages/backend-rs/src/misc/password.rs | 2 +- packages/backend-rs/src/misc/reaction.rs | 2 +- packages/backend-rs/src/misc/should_nyaify.rs | 2 +- .../src/service/antenna/check_hit.rs | 2 +- .../src/service/antenna/process_new_note.rs | 2 +- .../src/service/push_notification.rs | 2 +- packages/backend-rs/src/service/stream.rs | 2 +- packages/backend-rs/src/util/error_chain.rs | 2 +- packages/backend-rs/src/util/http_client.rs | 2 +- packages/macro-rs/macros-impl/src/error.rs | 41 +++++++++++++++++++ packages/macro-rs/macros-impl/src/lib.rs | 1 + packages/macro-rs/macros/src/lib.rs | 10 +++++ 20 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 packages/macro-rs/macros-impl/src/error.rs diff --git a/packages/backend-rs/src/database/cache.rs b/packages/backend-rs/src/database/cache.rs index 515053ef6c..d56da7f680 100644 --- a/packages/backend-rs/src/database/cache.rs +++ b/packages/backend-rs/src/database/cache.rs @@ -14,7 +14,7 @@ pub enum Category { Test, } -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[error("failed to execute Redis command")] Redis(#[from] RedisError), diff --git a/packages/backend-rs/src/database/redis.rs b/packages/backend-rs/src/database/redis.rs index 7fa7255b47..a17271f44f 100644 --- a/packages/backend-rs/src/database/redis.rs +++ b/packages/backend-rs/src/database/redis.rs @@ -82,7 +82,7 @@ async fn init_conn_pool() -> Result<(), RedisError> { Ok(()) } -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum RedisConnError { #[error("failed to initialize Redis connection pool")] Redis(RedisError), diff --git a/packages/backend-rs/src/federation/internal_actor/cache.rs b/packages/backend-rs/src/federation/internal_actor/cache.rs index 80f0ad22bc..de250f3d20 100644 --- a/packages/backend-rs/src/federation/internal_actor/cache.rs +++ b/packages/backend-rs/src/federation/internal_actor/cache.rs @@ -7,7 +7,7 @@ use crate::{database::db_conn, model::entity::user}; use sea_orm::prelude::*; use std::sync::Mutex; -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[error(transparent)] #[doc = "database error"] diff --git a/packages/backend-rs/src/federation/nodeinfo/fetch.rs b/packages/backend-rs/src/federation/nodeinfo/fetch.rs index c237a893fb..e7bdb0b071 100644 --- a/packages/backend-rs/src/federation/nodeinfo/fetch.rs +++ b/packages/backend-rs/src/federation/nodeinfo/fetch.rs @@ -7,7 +7,7 @@ use isahc::AsyncReadResponseExt; use serde::Deserialize; /// Errors that can occur while fetching NodeInfo from a remote server -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[error("failed to acquire an HTTP client")] HttpClient(#[from] http_client::Error), diff --git a/packages/backend-rs/src/federation/nodeinfo/generate.rs b/packages/backend-rs/src/federation/nodeinfo/generate.rs index 6cad9e59ae..4ab7ef65fa 100644 --- a/packages/backend-rs/src/federation/nodeinfo/generate.rs +++ b/packages/backend-rs/src/federation/nodeinfo/generate.rs @@ -153,7 +153,7 @@ pub async fn nodeinfo_2_0() -> Result<Nodeinfo20, DbErr> { } #[cfg(any(test, doctest, feature = "napi"))] -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[doc = "database error"] #[error(transparent)] diff --git a/packages/backend-rs/src/misc/convert_host.rs b/packages/backend-rs/src/misc/convert_host.rs index 0de4d1912d..fff1f9fb4c 100644 --- a/packages/backend-rs/src/misc/convert_host.rs +++ b/packages/backend-rs/src/misc/convert_host.rs @@ -2,7 +2,7 @@ // We may want to (re)implement these functions in the `federation` module // in a Rusty way (e.g., traits of actor type) if needed. -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[doc = "UTS #46 process has failed"] #[error(transparent)] diff --git a/packages/backend-rs/src/misc/get_image_size.rs b/packages/backend-rs/src/misc/get_image_size.rs index bc5222f054..a6c06df5f9 100644 --- a/packages/backend-rs/src/misc/get_image_size.rs +++ b/packages/backend-rs/src/misc/get_image_size.rs @@ -5,7 +5,7 @@ use nom_exif::{parse_jpeg_exif, EntryValue, ExifTag}; use std::io::Cursor; use tokio::sync::Mutex; -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[error("Redis cache operation has failed")] Cache(#[from] cache::Error), diff --git a/packages/backend-rs/src/misc/latest_version.rs b/packages/backend-rs/src/misc/latest_version.rs index 1f330f4d2e..f49ac81099 100644 --- a/packages/backend-rs/src/misc/latest_version.rs +++ b/packages/backend-rs/src/misc/latest_version.rs @@ -4,7 +4,7 @@ use crate::{database::cache, util::http_client}; use isahc::AsyncReadResponseExt; use serde::Deserialize; -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[error("Redis cache operation has failed")] Cache(#[from] cache::Error), diff --git a/packages/backend-rs/src/misc/password.rs b/packages/backend-rs/src/misc/password.rs index bc2025f275..8d6be4101e 100644 --- a/packages/backend-rs/src/misc/password.rs +++ b/packages/backend-rs/src/misc/password.rs @@ -15,7 +15,7 @@ pub fn hash_password(password: &str) -> Result<String, password_hash::errors::Er .to_string()) } -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[error("failed to verify password against bcrypt hash")] Bcrypt(#[from] bcrypt::BcryptError), diff --git a/packages/backend-rs/src/misc/reaction.rs b/packages/backend-rs/src/misc/reaction.rs index e6b699d59a..afae0a66ac 100644 --- a/packages/backend-rs/src/misc/reaction.rs +++ b/packages/backend-rs/src/misc/reaction.rs @@ -53,7 +53,7 @@ pub fn count_reactions(reactions: &HashMap<String, u32>) -> HashMap<String, u32> res } -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[doc = "UTS #46 process has failed"] #[error(transparent)] diff --git a/packages/backend-rs/src/misc/should_nyaify.rs b/packages/backend-rs/src/misc/should_nyaify.rs index bf4166f18d..8476678c77 100644 --- a/packages/backend-rs/src/misc/should_nyaify.rs +++ b/packages/backend-rs/src/misc/should_nyaify.rs @@ -6,7 +6,7 @@ use crate::{ }; use sea_orm::{DbErr, EntityTrait, QuerySelect, SelectColumns}; -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[doc = "database error"] #[error(transparent)] diff --git a/packages/backend-rs/src/service/antenna/check_hit.rs b/packages/backend-rs/src/service/antenna/check_hit.rs index 794b2f794e..0ef8f13595 100644 --- a/packages/backend-rs/src/service/antenna/check_hit.rs +++ b/packages/backend-rs/src/service/antenna/check_hit.rs @@ -6,7 +6,7 @@ use crate::{ }; use sea_orm::{prelude::*, QuerySelect}; -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum AntennaCheckError { #[doc = "database error"] #[error(transparent)] diff --git a/packages/backend-rs/src/service/antenna/process_new_note.rs b/packages/backend-rs/src/service/antenna/process_new_note.rs index 0588c3c3f3..d9099f867f 100644 --- a/packages/backend-rs/src/service/antenna/process_new_note.rs +++ b/packages/backend-rs/src/service/antenna/process_new_note.rs @@ -13,7 +13,7 @@ use crate::{ use redis::{streams::StreamMaxlen, AsyncCommands, RedisError}; use sea_orm::prelude::*; -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[doc = "database error"] #[error(transparent)] diff --git a/packages/backend-rs/src/service/push_notification.rs b/packages/backend-rs/src/service/push_notification.rs index cfe1d99ae8..cbf3be0793 100644 --- a/packages/backend-rs/src/service/push_notification.rs +++ b/packages/backend-rs/src/service/push_notification.rs @@ -13,7 +13,7 @@ use sea_orm::prelude::*; use serde::Deserialize; use web_push::*; -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[doc = "database error"] #[error(transparent)] diff --git a/packages/backend-rs/src/service/stream.rs b/packages/backend-rs/src/service/stream.rs index 25f5802eef..d1acbfa4a7 100644 --- a/packages/backend-rs/src/service/stream.rs +++ b/packages/backend-rs/src/service/stream.rs @@ -62,7 +62,7 @@ pub enum ChatEvent { Typing, } -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[error("failed to execute a Redis command")] Redis(#[from] RedisError), diff --git a/packages/backend-rs/src/util/error_chain.rs b/packages/backend-rs/src/util/error_chain.rs index d19c99ae76..59af604578 100644 --- a/packages/backend-rs/src/util/error_chain.rs +++ b/packages/backend-rs/src/util/error_chain.rs @@ -34,7 +34,7 @@ mod unit_test { #[error("unexpected string '{0}'")] struct InnerError2(String); - #[derive(thiserror::Error, Debug)] + #[macros::errors] enum ErrorVariants { #[error("error 1 occured")] Error1(#[from] InnerError1), diff --git a/packages/backend-rs/src/util/http_client.rs b/packages/backend-rs/src/util/http_client.rs index 3b56d57c6e..0347334b35 100644 --- a/packages/backend-rs/src/util/http_client.rs +++ b/packages/backend-rs/src/util/http_client.rs @@ -5,7 +5,7 @@ use isahc::{config::*, HttpClient}; use once_cell::sync::OnceCell; use std::time::Duration; -#[derive(thiserror::Error, Debug)] +#[macros::errors] pub enum Error { #[error("HTTP request failed")] Isahc(#[from] isahc::Error), diff --git a/packages/macro-rs/macros-impl/src/error.rs b/packages/macro-rs/macros-impl/src/error.rs new file mode 100644 index 0000000000..a5d6fe4d38 --- /dev/null +++ b/packages/macro-rs/macros-impl/src/error.rs @@ -0,0 +1,41 @@ +use proc_macro2::TokenStream; +use quote::quote; + +pub fn error_variants(_attr: TokenStream, item: TokenStream) -> TokenStream { + match error_variants_impl(item) { + Ok(tokens) => tokens, + Err(error) => error.to_compile_error(), + } +} + +fn error_variants_impl(item: TokenStream) -> syn::Result<TokenStream> { + let items: syn::ItemEnum = syn::parse2(item.clone())?; + let mut new_item = items.clone(); + + new_item.variants = items + .variants + .into_iter() + .map(|mut variant| { + // check if doc attribute is alredy there + if variant.attrs.iter().any(|attr| attr.path().is_ident("doc")) { + return variant; + } + + let msg = variant.attrs.iter().find_map(|attr| { + if !attr.path().is_ident("error") { + return None; + } + let lit: syn::LitStr = attr.parse_args().ok()?; + Some(lit.value()) + }); + + if let Some(msg) = msg { + variant.attrs.push(syn::parse_quote! { #[doc = #msg] }); + } + + variant + }) + .collect(); + + Ok(quote! { #new_item }) +} diff --git a/packages/macro-rs/macros-impl/src/lib.rs b/packages/macro-rs/macros-impl/src/lib.rs index 9e4a70240e..4d9cde075b 100644 --- a/packages/macro-rs/macros-impl/src/lib.rs +++ b/packages/macro-rs/macros-impl/src/lib.rs @@ -1,4 +1,5 @@ #![allow(clippy::items_after_test_module)] +pub mod error; pub mod napi; mod util; diff --git a/packages/macro-rs/macros/src/lib.rs b/packages/macro-rs/macros/src/lib.rs index cadb00475d..3619839a74 100644 --- a/packages/macro-rs/macros/src/lib.rs +++ b/packages/macro-rs/macros/src/lib.rs @@ -75,10 +75,20 @@ define_wrapper_proc_macro_attributes! { #[cfg(any(test, doctest))] #item } + + /// When applied to error variant enums, this macro generates a document + /// based on error messages unless there is a doc comment + errors(attr, item) { + #[derive(::thiserror::Error, ::std::fmt::Debug)] + #[macros::error_variants(#attr, #item)] + #item + } } reexport_proc_macro_attributes! { /// Creates an extra wrapper function for [napi_derive](https://docs.rs/napi-derive/latest/napi_derive/). /// See [macros_impl::napi::napi] for details. macros_impl::napi::napi as napi + + macros_impl::error::error_variants as error_variants }