From f5e04fce16001d73063c8768e31e0dd181a98db2 Mon Sep 17 00:00:00 2001 From: Tait Hoyem Date: Sat, 22 Apr 2023 17:28:24 -0600 Subject: [PATCH] Please clippy --- Cargo.lock | 33 +----- Cargo.toml | 2 - src/filters.rs | 74 +++++++------ src/languages.rs | 48 ++++----- src/main.rs | 59 +++------- src/model.rs | 120 --------------------- src/views.rs | 27 +++-- templates/partials/play_by_play_table.html | 2 +- 8 files changed, 92 insertions(+), 273 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40e6e99..1171941 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -383,15 +383,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -534,7 +525,7 @@ version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "convert_case 0.4.0", + "convert_case", "proc-macro2", "quote", "rustc_version", @@ -1132,8 +1123,6 @@ dependencies = [ "lazy_static", "once_cell", "ormx", - "rename", - "rename-item", "rust-embed", "rust-i18n", "serde", @@ -1735,26 +1724,6 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" -[[package]] -name = "rename" -version = "0.1.1" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rename-item" -version = "0.1.0" -dependencies = [ - "convert_case 0.6.0", - "darling", - "heck", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "ring" version = "0.16.20" diff --git a/Cargo.toml b/Cargo.toml index 9a15af2..850b49c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,8 +33,6 @@ i18n-embed-fl = "0.6.6" rust-embed = { version = "6.6.1", features = ["axum"] } lazy_static = "1.4.0" ibihf-macros = { version = "0.1.0", path = "ibihf-macros" } -rename = { version = "0.1.1", path = "../rename-rs" } -rename-item = { version = "0.1.0", path = "../rename-item" } [dev-dependencies] tokio-test = "0.4.2" diff --git a/src/filters.rs b/src/filters.rs index 57ae40d..c175f86 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -1,3 +1,9 @@ +// We must always wrap a return type of a filter in a Result. +// This sometimes triggers a clippy warning. +#![allow(clippy::unnecessary_wraps)] +// We must always take references, even when it's not technically the fastest thing to do. +// This sometimes also causes a clippy warning. +#![allow(clippy::trivially_copy_pass_by_ref)] use crate::{ Player, ShotDetails, @@ -8,7 +14,7 @@ use crate::{ pub fn seconds_as_time(secs: &i32) -> ::askama::Result { let minutes = secs / 60; let seconds = secs % 60; - Ok(format!("{}:{}", minutes, seconds)) + Ok(format!("{minutes}:{seconds}")) } pub fn player_name(player: &Player) -> ::askama::Result { Ok(format!("{} {}", initials(&player.first_names)?, &player.last_name)) @@ -17,48 +23,40 @@ pub fn goal_player_name(goal: &GoalDetails) -> ::askama::Result { Ok(format!("{} {}", initials(&goal.player_first_names)?, &goal.player_last_name)) } pub fn goal_assist_name(goal: &GoalDetails, lang: &SupportedLanguage) -> ::askama::Result { - let initials = match goal.first_assist_first_names { - Some(ref f_names) => initials(f_names)?, - None => return Ok(lang.lookup("not-applicable")), - }; - let last_name = match goal.first_assist_last_name { - Some(ref l_name) => l_name, - None => return Ok(lang.lookup("not-applicable")), - }; - Ok(format!("{} {}", initials, last_name)) + let Some(ref f_names) = goal.second_assist_first_names else { + return Ok(lang.lookup("not-applicable")); + }; + let Some(ref l_name) = goal.second_assist_last_name else { + return Ok(lang.lookup("not-applicable")); + }; + Ok(format!("{f_names} {l_name}")) } pub fn shot_assist_name(goal: &ShotDetails, lang: &SupportedLanguage) -> ::askama::Result { - let initials = match goal.first_assist_first_names { - Some(ref f_names) => initials(&f_names)?, - None => return Ok(lang.lookup("not-applicable")), - }; - let last_name = match goal.first_assist_last_name { - Some(ref l_name) => l_name, - None => return Ok(lang.lookup("not-applicable")), - }; - Ok(format!("{} {}", initials, last_name)) + let Some(ref f_names) = goal.second_assist_first_names else { + return Ok(lang.lookup("not-applicable")); + }; + let Some(ref l_name) = goal.second_assist_last_name else { + return Ok(lang.lookup("not-applicable")); + }; + Ok(format!("{f_names} {l_name}")) } pub fn goal_second_assist_name(goal: &GoalDetails, lang: &SupportedLanguage) -> ::askama::Result { - let initials = match goal.second_assist_first_names { - Some(ref f_names) => initials(f_names)?, - None => return Ok(lang.lookup("not-applicable")), - }; - let last_name = match goal.second_assist_last_name { - Some(ref l_name) => l_name, - None => return Ok(lang.lookup("not-applicable")), - }; - Ok(format!("{} {}", initials, last_name)) + let Some(ref f_names) = goal.second_assist_first_names else { + return Ok(lang.lookup("not-applicable")); + }; + let Some(ref l_name) = goal.second_assist_last_name else { + return Ok(lang.lookup("not-applicable")); + }; + Ok(format!("{f_names} {l_name}")) } pub fn shot_second_assist_name(goal: &ShotDetails, lang: &SupportedLanguage) -> ::askama::Result { - let initials = match goal.second_assist_first_names { - Some(ref f_names) => initials(f_names)?, - None => return Ok(lang.lookup("not-applicable")), - }; - let last_name = match goal.second_assist_last_name { - Some(ref l_name) => l_name, - None => return Ok(lang.lookup("not-applicable")), - }; - Ok(format!("{} {}", initials, last_name)) + let Some(ref f_names) = goal.second_assist_first_names else { + return Ok(lang.lookup("not-applicable")); + }; + let Some(ref l_name) = goal.second_assist_last_name else { + return Ok(lang.lookup("not-applicable")); + }; + Ok(format!("{f_names} {l_name}")) } pub fn shot_player_name(shot: &ShotDetails) -> ::askama::Result { Ok(format!("{} {}", initials(&shot.player_first_names)?, &shot.player_last_name)) @@ -72,7 +70,7 @@ pub fn initials(first_names: &str) -> ::askama::Result { } pub fn nullable(ot: &Option) -> ::askama::Result { match ot { - Some(t) => Ok(format!("{}", t)), + Some(t) => Ok(format!("{t}")), None => Ok("NULL".to_string()) } } diff --git a/src/languages.rs b/src/languages.rs index edb761d..05cda4d 100644 --- a/src/languages.rs +++ b/src/languages.rs @@ -33,49 +33,49 @@ pub enum SupportedLanguage { #[display(fmt = "fr-ca")] French = 2, } -impl Into for SupportedLanguage { - fn into(self) -> i32 { - match self { - Self::English => 1, - Self::French => 2, - } - } +impl From for i32 { + fn from(lang: SupportedLanguage) -> Self { + match lang { + SupportedLanguage::English => 1, + SupportedLanguage::French => 2, + } + } } impl From for FluentValue<'_> { fn from(n: SupportedLanguage) -> Self { n.to_string().into() } } -impl Into for SupportedLanguage { - fn into(self) -> LanguageIdentifier { - match self { - Self::English => langid!("en-ca"), - Self::French => langid!("fr-ca"), +impl From for LanguageIdentifier { + fn from(lang: SupportedLanguage) -> LanguageIdentifier { + match lang { + SupportedLanguage::English => langid!("en-ca"), + SupportedLanguage::French => langid!("fr-ca"), } } } -impl<'a> Into> for SupportedLanguage { - fn into(self) -> Locale<'a> { - Locale::new(self.into(), &LOCALES) - } +impl<'a> From for Locale<'a> { + fn from(lang: SupportedLanguage) -> Self { + Locale::new(lang.into(), &LOCALES) + } } impl SupportedLanguage { - pub fn lookup(&self, key: &str) -> String { + pub fn lookup(self, key: &str) -> String { LOCALES - .lookup(&(*self).into(), key) + .lookup(&self.into(), key) .expect("Unable to find key {key} in locale {self}.") } - pub fn other_langs(&self) -> impl Iterator + '_ { - Self::iter().filter(move |lang| lang != self) + pub fn other_langs(self) -> impl Iterator + 'static { + Self::iter().filter(move |lang| lang != &self) } - pub fn native_name(&self) -> String { + pub fn native_name(self) -> String { match self { Self::English => "English", Self::French => "Français", } .to_string() } - pub fn id(&self) -> i32 { + pub fn id(self) -> i32 { match self { Self::English => 1, Self::French => 2, @@ -105,8 +105,8 @@ impl LocalizedName { }) // if not found, replace it with ANY localization of the word; this will help when, for example, there is no matching name for a French game, but the game has already been created with the English name. // if NO localization is found, then we can still return a None value; but hopefully through database, form, and web server restrictions, we can mostly stop that from happening - .or_else(|| if self.localizations.len() >= 1 { - Some(self.localizations.values().nth(0).unwrap().to_string()) + .or_else(|| if self.localizations.is_empty() { + Some(self.localizations.values().next().unwrap().to_string()) } else { None }) diff --git a/src/main.rs b/src/main.rs index d273a8f..dc57417 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,9 @@ +#![warn( + clippy::all, + clippy::pedantic, + unsafe_code, +)] + mod db; mod filters; mod languages; @@ -254,10 +260,9 @@ async fn main() { &SupportedLanguage::French.lookup(GameScorePageTemplate::URL_KEY), get(score_for_game_html), ) - //.route("/:lang/player/:name/", get(player_from_name)) .with_state(state); let addr = SocketAddr::from(([127, 0, 0, 1], 8000)); - println!("Listening on {}", addr); + println!("Listening on {addr}"); axum::Server::bind(&addr) .serve(router.into_make_service()) .await @@ -275,42 +280,12 @@ async fn language_list(State(server_config): State) -> impl IntoRes (StatusCode::OK, lang_list_tmpl) } -async fn player_from_name( - State(server_config): State, - Path((lang, name)): Path<(SupportedLanguage, String)>, -) -> impl IntoResponse { - let player = Player::from_name_case_insensitive(&server_config.db_pool, name.clone()) - .await - .unwrap(); - let latest_league = Player::latest_league(&server_config.db_pool, player.id, lang.into()) - .await - .unwrap() - .unwrap(); - let latest_league_stats = - League::player_stats(&server_config.db_pool, player.id, latest_league.id) - .await - .unwrap(); - let lifetime_stats = Player::lifetime_stats(&server_config.db_pool, player.id) - .await - .unwrap(); - let html = PlayerPageTemplate { - player, - lang_links: other_lang_urls!(lang, PlayerPageTemplate), - locale: lang.into(), - league: latest_league, - league_stats: latest_league_stats, - lifetime_stats, - lang, - }; - (StatusCode::OK, html) -} - /* macro_rules! get_all { ($crud_struct:ident, $func_name:ident) => { #[debug_handler] async fn $func_name(State(server_config): State) -> impl IntoResponse { - let cruder = $crud_struct::all(&*server_config.db_pool).await.unwrap(); + let cruder = $crud_struct::all(&server_config.db_pool).await.unwrap(); (StatusCode::OK, Json(cruder)) } }; @@ -322,7 +297,7 @@ macro_rules! get_by_id { State(server_config): State, Path(id): Path, ) -> impl IntoResponse { - let cruder = $crud_struct::get(&*server_config.db_pool, id) + let cruder = $crud_struct::get(&server_config.db_pool, id) .await .unwrap(); (StatusCode::OK, Json(cruder)) @@ -335,7 +310,7 @@ async fn league_html( State(server_config): State, Path(lang): Path, ) -> impl IntoResponse { - let leagues = League::all(&*server_config.db_pool, lang.into()).await.unwrap(); + let leagues = League::all(&server_config.db_pool, lang.into()).await.unwrap(); let leagues_template = LeagueListTemplate { lang_links: other_lang_urls!(lang, LeagueListTemplate), locale: lang.into(), @@ -349,11 +324,11 @@ async fn divisions_for_league_html( State(server_config): State, Path((lang, league_id)): Path<(SupportedLanguage, i32)>, ) -> impl IntoResponse { - let league = League::get(&*server_config.db_pool, league_id, lang.into()) + let league = League::get(&server_config.db_pool, league_id, lang.into()) .await .unwrap() .unwrap(); - let divisions = Division::by_league(&*server_config.db_pool, league_id, lang.into()) + let divisions = Division::by_league(&server_config.db_pool, league_id, lang.into()) .await .unwrap(); let html = DivisionListTemplate { @@ -371,14 +346,14 @@ async fn games_for_division_html( State(server_config): State, Path((lang, division_id)): Path<(SupportedLanguage, i32)>, ) -> impl IntoResponse { - let division = Division::get(&*server_config.db_pool, division_id, lang.into()) + let division = Division::get(&server_config.db_pool, division_id, lang.into()) .await .unwrap() .unwrap(); - let games = Game::by_division(&*server_config.db_pool, division.id, lang.into()) + let games = Game::by_division(&server_config.db_pool, division.id, lang.into()) .await .unwrap(); - let iihf_stats = division.iihf_stats(&*server_config.db_pool, lang.into()).await.unwrap(); + let iihf_stats = division.iihf_stats(&server_config.db_pool, lang.into()).await.unwrap(); let games_template = GameListTemplate { locale: lang.into(), lang_links: other_lang_urls!(lang, GameListTemplate, "id" => division_id), @@ -396,10 +371,10 @@ async fn score_for_game_html( State(server_config): State, Path((lang, game_id)): Path<(SupportedLanguage, i32)>, ) -> impl IntoResponse { - let game = Game::get(&*server_config.db_pool, game_id, lang.into()) + let game = Game::get(&server_config.db_pool, game_id, lang.into()) .await .unwrap().unwrap(); - let division = Division::get(&*server_config.db_pool, game.division, lang.into()) + let division = Division::get(&server_config.db_pool, game.division, lang.into()) .await .unwrap() .unwrap(); diff --git a/src/model.rs b/src/model.rs index 6f1fe2e..c907ef0 100644 --- a/src/model.rs +++ b/src/model.rs @@ -10,21 +10,6 @@ pub trait NameTableName { const NAME_TABLE_NAME: &'static str; const NAME_TABLE_FK_NAME: &'static str; } -macro_rules! impl_table_name { - ($ty:ident, $tname:literal) => { - impl TableName for $ty { - const TABLE_NAME: &'static str = $tname; - } - }; -} -macro_rules! impl_name_table_name { - ($ty:ident, $tname:literal, $fk_name:literal) => { - impl NameTableName for $ty { - const NAME_TABLE_NAME: &'static str = $tname; - const NAME_TABLE_FK_NAME: &'static str = $fk_name; - } - }; -} #[derive(FromRow, Serialize, Deserialize, Debug, ormx::Table)] #[ormx(table = "supported_languages", id = id, insertable, deletable)] @@ -35,111 +20,6 @@ pub struct Language { pub short_name: String, } -macro_rules! impl_localized_get { - ($struct:ident, $func:ident) => { - impl $struct { - pub async fn get(pool: &sqlx::PgPool, id: i32, lang: crate::SupportedLanguage) -> Result, sqlx::Error> { - let query = const_format::formatcp!(r#" -SELECT - {0}.*, - {1}({0}.id, $2) AS name -FROM {0} -WHERE {0}.id = $1;"#, - stringify!(<$struct as TableName>::TABLE_NAME), - stringify!($func), - ); - sqlx::query_as::<_, $struct>(&query) - .bind(id) - .bind(lang) - .fetch_optional(pool) - .await - } - } - }; -} -macro_rules! impl_localized_get_by_many { - ($struct:ident, $by:ident) => { - impl $struct { - #[rename::rename_fn(prepend="by_")] - pub async fn $by(pool: &sqlx::PgPool, by: i32, lang: crate::SupportedLanguage) -> Result, sqlx::Error> { - let query = format!(r#" -SELECT - {0}.*, - -- if available, use the localized name, - -- if not, choose the default name (in English, CA) - -- if not, see if there is any name attached (there should be at least some language selected) - COALESCE( - localized_name.name, - default_name.name, - any_name.name - ) AS name -FROM {0} --- search for the proper, localized name -LEFT JOIN {1} localized_name - ON localized_name.{2} = {0}.id - AND localized_name.language = $2 --- also look for the name in the default language (English, CA) -LEFT JOIN {1} default_name - ON default_name.{2} = {0}.id - AND default_name.language=1 --- also look for ANY matching name in ANY locale -LEFT JOIN {1} any_name - ON any_name.{2} = {0}.id -WHERE {0}.{3} = $1;"#, - <$struct as TableName>::TABLE_NAME, - <$struct as NameTableName>::NAME_TABLE_NAME, - <$struct as NameTableName>::NAME_TABLE_FK_NAME, - stringify!($by), - ); - sqlx::query_as::<_, $struct>(&query) - .bind(by) - .bind(lang) - .fetch_all(pool) - .await - } - } - }; -} -macro_rules! impl_localized_all { - ($struct:ident) => { - impl $struct { - pub async fn all(pool: &sqlx::PgPool, lang: crate::SupportedLanguage) -> Result, sqlx::Error> { - let query = format!(r#" -SELECT - {0}.*, - -- if available, use the localized name, - -- if not, choose the default name (in English, CA) - -- if not, see if there is any name attached (there should be at least some language selected) - COALESCE( - localized_name.name, - default_name.name, - any_name.name - ) AS name -FROM {0} --- search for the proper, localized name -LEFT JOIN {1} localized_name - ON localized_name.{2} = {0}.id - AND localized_name.language = $1 --- also look for the name in the default language (English, CA) -LEFT JOIN {1} default_name - ON default_name.{2} = {0}.id - AND default_name.language=1 --- also look for ANY matching name in ANY locale -LEFT JOIN {1} any_name - ON any_name.{2} = {0}.id;"#, - <$struct as TableName>::TABLE_NAME, - <$struct as NameTableName>::NAME_TABLE_NAME, - <$struct as NameTableName>::NAME_TABLE_FK_NAME, - ); - sqlx::query_as::<_, $struct>(&query) - .bind(lang) - .fetch_all(pool) - .await - } - } - }; -} - #[derive(FromRow, Serialize, Deserialize, Debug, NameTableName)] #[table_names(table_name = "leagues", name_func = "league_name", name_table_name = "league_names", name_table_name_fk = "league")] pub struct League { diff --git a/src/views.rs b/src/views.rs index 691b050..9d6fa30 100644 --- a/src/views.rs +++ b/src/views.rs @@ -1,7 +1,6 @@ #![allow(dead_code)] use crate::model::{Division, Game, League, Player}; -use crate::languages::SupportedLanguage; use serde::{Deserialize, Serialize}; use sqlx::FromRow; use sqlx::PgPool; @@ -35,19 +34,19 @@ pub struct IihfStatsI64 { pub ties: i64, pub points: i64, } -impl Into for IihfStats { - fn into(self) -> IihfStatsI64 { +impl From for IihfStatsI64 { + fn from(val: IihfStats) -> Self { IihfStatsI64 { - team_name: self.team_name.clone(), - team_id: self.team_id, - reg_wins: self.reg_wins.into(), - reg_losses: self.reg_losses.into(), - ot_wins: self.ot_wins.into(), - ot_losses: self.ot_losses.into(), - ties: self.ties.into(), - points: self.points.into(), - } - } + team_name: val.team_name.clone(), + team_id: val.team_id, + reg_wins: val.reg_wins.into(), + reg_losses: val.reg_losses.into(), + ot_wins: val.ot_wins.into(), + ot_losses: val.ot_losses.into(), + ties: val.ties.into(), + points: val.points.into(), + } + } } #[derive(FromRow, Deserialize, Serialize, Debug)] @@ -459,7 +458,7 @@ impl Player { shots.period_time ASC LIMIT 5; "#; - sqlx::query_as::<_, GoalDetails>(&query) + sqlx::query_as::<_, GoalDetails>(query) .bind(id) .bind(lang) .fetch_all(pool) diff --git a/templates/partials/play_by_play_table.html b/templates/partials/play_by_play_table.html index 9a8eda3..9826b77 100644 --- a/templates/partials/play_by_play_table.html +++ b/templates/partials/play_by_play_table.html @@ -12,7 +12,7 @@ {% for shot in shots %} - {{ shot.player_first_names|initials }} {{ shot.player_last_name }} + {{ shot|shot_player_name }} {{ shot.team_name }} {{ shot.player_number }}