From 33368caf425d7674ab0611b516ada2548d4e1948 Mon Sep 17 00:00:00 2001 From: Shark Date: Sat, 11 May 2024 18:11:35 +0200 Subject: [PATCH 1/6] make clippy more strict --- Cargo.toml | 31 ++++++ clippy.toml | 1 + crates/gosub_bindings/Cargo.toml | 4 + crates/gosub_bindings/src/lib.rs | 22 ++--- crates/gosub_bindings/src/wrapper.rs | 2 +- crates/gosub_bindings/src/wrapper/node.rs | 2 + crates/gosub_bindings/src/wrapper/text.rs | 2 +- crates/gosub_config/src/errors.rs | 2 +- crates/gosub_config/src/lib.rs | 31 +++--- crates/gosub_config/src/settings.rs | 97 ++++++++++--------- crates/gosub_config/src/storage/json.rs | 2 +- crates/gosub_config/src/storage/sqlite.rs | 4 +- crates/gosub_html5/src/element_class.rs | 14 ++- crates/gosub_html5/src/errors.rs | 2 +- crates/gosub_html5/src/node.rs | 46 +++++---- crates/gosub_html5/src/node/arena.rs | 5 +- crates/gosub_html5/src/node/data/comment.rs | 3 +- crates/gosub_html5/src/node/data/doctype.rs | 2 +- crates/gosub_html5/src/node/data/document.rs | 2 +- crates/gosub_html5/src/node/data/element.rs | 3 +- crates/gosub_html5/src/node/data/text.rs | 3 +- crates/gosub_html5/src/parser/helper.rs | 1 + crates/gosub_html5/src/parser/query.rs | 4 +- crates/gosub_html5/src/parser/quirks.rs | 2 +- crates/gosub_html5/src/parser/tree_builder.rs | 6 +- crates/gosub_html5/src/tokenizer/state.rs | 2 +- .../gosub_html5/src/tokenizer/test_cases.rs | 7 +- crates/gosub_jsapi/Cargo.toml | 4 + crates/gosub_jsapi/src/console.rs | 11 ++- .../src/console/writable_printer.rs | 2 +- crates/gosub_net/src/dns.rs | 21 ++-- crates/gosub_net/src/dns/cache.rs | 6 +- crates/gosub_net/src/http/request.rs | 7 +- crates/gosub_net/src/http/response.rs | 13 +-- crates/gosub_render_utils/Cargo.toml | 5 + crates/gosub_render_utils/src/render_tree.rs | 29 +++--- .../src/render_tree/properties.rs | 14 +-- .../src/render_tree/text.rs | 23 +++-- crates/gosub_shared/Cargo.toml | 7 +- crates/gosub_shared/src/timing.rs | 21 ++-- crates/gosub_shared/src/types.rs | 2 +- crates/gosub_testing/Cargo.toml | 7 +- .../src/testing/tree_construction.rs | 5 +- .../src/testing/tree_construction/fixture.rs | 3 +- .../src/testing/tree_construction/parser.rs | 36 +++---- .../src/testing/tree_construction/result.rs | 5 +- crates/gosub_vello/src/render.rs | 2 +- crates/gosub_webexecutor/Cargo.toml | 7 +- crates/gosub_webexecutor/src/js.rs | 2 +- .../src/js/value_conversion.rs | 4 +- crates/gosub_webexecutor/tests/interop.rs | 30 +++--- crates/gosub_webinterop/Cargo.toml | 5 + crates/gosub_webinterop/src/function.rs | 2 +- crates/gosub_webinterop/src/impl_function.rs | 2 +- crates/gosub_webinterop/src/lib.rs | 22 ++--- crates/gosub_webinterop/src/property.rs | 42 +++----- crates/gosub_webinterop/src/types.rs | 12 +-- crates/gosub_webinterop/src/types/args.rs | 28 +++--- crates/gosub_webinterop/src/types/executor.rs | 8 +- crates/gosub_webinterop/src/types/field.rs | 4 +- crates/gosub_webinterop/src/types/generics.rs | 32 +++--- .../gosub_webinterop/src/types/primitive.rs | 24 ++--- crates/gosub_webinterop/src/types/slice.rs | 2 +- crates/gosub_webinterop/src/types/ty.rs | 26 ++--- src/bin/config-store.rs | 18 ++-- src/bin/gosub-parser.rs | 9 +- src/bin/html5-parser-test.rs | 15 ++- src/bin/run-js.rs | 1 + 68 files changed, 455 insertions(+), 365 deletions(-) create mode 100644 clippy.toml diff --git a/Cargo.toml b/Cargo.toml index 47b88c26c..56e744f05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,3 +95,34 @@ codegen-units = 1 [lib] crate-type = ["staticlib", "cdylib", "rlib"] + + + +[lints] +workspace = true + +[workspace.lints.clippy] +panic = "deny" +perf = { level = "deny", priority = -1 } +unwrap_used = "deny" +pedantic = { level = "warn", priority = -1 } +nursery = { level = "warn", priority = -1 } +cargo = { level = "warn", priority = -1 } +clone_on_ref_ptr = "warn" +empty_enum_variants_with_brackets = "warn" +empty_structs_with_brackets = "warn" +enum_glob_use = "warn" +error_impl_error = "warn" +format_push_string = "warn" +infinite_loop = "warn" +rc_buffer = "warn" +rc_mutex = "warn" +expect_used = "warn" +missing_docs_in_private_items = "allow" +cargo_common_metadata = "allow" # should be removed if we release our crates to crates.io +cast_possible_truncation = "allow" # should this be on allow? +cast_precision_loss = "allow" +cast_sign_loss = "allow" +cast_possible_wrap = "allow" +or_fun_call = "allow" +multiple_crate_versions = "allow" # should this be on allow? \ No newline at end of file diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 000000000..154626ef4 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +allow-unwrap-in-tests = true diff --git a/crates/gosub_bindings/Cargo.toml b/crates/gosub_bindings/Cargo.toml index e6d390d72..861d6eeb3 100644 --- a/crates/gosub_bindings/Cargo.toml +++ b/crates/gosub_bindings/Cargo.toml @@ -12,3 +12,7 @@ gosub_html5 = { path = "../gosub_html5" } [lib] crate-type = ["staticlib"] + + +[lints] +workspace = true \ No newline at end of file diff --git a/crates/gosub_bindings/src/lib.rs b/crates/gosub_bindings/src/lib.rs index 0a61eb7c3..6410bcefb 100644 --- a/crates/gosub_bindings/src/lib.rs +++ b/crates/gosub_bindings/src/lib.rs @@ -19,8 +19,8 @@ use wrapper::node::CNode; /// to build a render tree. DO NOT take ownership of this pointer in Rust or the /// universe might collapse. /// -/// Moves an owning pointer to the rendertree using Box::into_raw() to the C API. -/// This pointer MUST be passed to gosub_rendertree_free() after usage for proper cleanup. +/// Moves an owning pointer to the rendertree using `Box::into_raw()` to the C API. +/// This pointer MUST be passed to `gosub_rendertree_free()` after usage for proper cleanup. #[no_mangle] pub unsafe extern "C" fn gosub_rendertree_init(html: *const c_char) -> *mut RenderTree { let html_str = unsafe { @@ -50,8 +50,8 @@ pub unsafe extern "C" fn gosub_rendertree_init(html: *const c_char) -> *mut Rend /// Construct a tree iterator for a render tree and return an owning pointer to it. /// /// # Safety -/// Moves an owning pointer to the tree iterator using Box::into_raw() to the C API. -/// This pointer MUST be passed to gosub_rendertree_iterator_free() after usage for proper cleanup. +/// Moves an owning pointer to the tree iterator using `Box::into_raw()` to the C API. +/// This pointer MUST be passed to `gosub_rendertree_iterator_free()` after usage for proper cleanup. #[no_mangle] pub unsafe extern "C" fn gosub_rendertree_iterator_init( rendertree: *const RenderTree, @@ -60,10 +60,10 @@ pub unsafe extern "C" fn gosub_rendertree_iterator_init( Box::into_raw(tree_iterator) } -/// Takes a tree_iterator and returns a non-owning pointer to the next node +/// Takes a `tree_iterator` and returns a non-owning pointer to the next node /// /// # Safety -/// Takes a tree_iterator pointer (owned by the C API generated by gosub_rendertree_iterator_init()) +/// Takes a `tree_iterator` pointer (owned by the C API generated by `gosub_rendertree_iterator_init()`) /// and modifies it to point to the next tree-order node in the tree. Any heap-allocated data /// on the current node is free'd before pointing to the next node. Returns a ready-only pointer /// to the next node. @@ -73,16 +73,16 @@ pub unsafe extern "C" fn gosub_rendertree_next_node( ) -> *const Node { let next = (*tree_iterator).next(); if let Some(next) = next { - next.as_ptr() as *const Node + next.as_ptr().cast_const() } else { ptr::null() } } -/// Fetch the node data according to the NodeType of the current node. +/// Fetch the node data according to the `NodeType` of the current node. /// /// # Safety -/// Uses a read-only pointer obtained from gosub_rendertree_next_node() +/// Uses a read-only pointer obtained from `gosub_rendertree_next_node()` /// and a mutable pointer owned by the C API to write (copy) the contents /// of the read-only pointer into the mutable pointer. #[no_mangle] @@ -93,7 +93,7 @@ pub unsafe extern "C" fn gosub_rendertree_get_node_data(node: *const Node, c_nod } } -/// Free the iterator pointer obtained from gosub_rendertree_iterator_init() +/// Free the iterator pointer obtained from `gosub_rendertree_iterator_init()` /// /// # Safety /// This takes ownership of the pointer from the C API and transfers it to Rust so it can @@ -103,7 +103,7 @@ pub unsafe extern "C" fn gosub_rendertree_iterator_free(tree_iterator: *mut Tree let _ = Box::from_raw(tree_iterator); } -/// Free the rendertree pointer obtained from gosub_rendertree_init() +/// Free the rendertree pointer obtained from `gosub_rendertree_init()` /// /// # Safety /// This takes ownership of the pointer from the C API and transfers it to Rust so it can diff --git a/crates/gosub_bindings/src/wrapper.rs b/crates/gosub_bindings/src/wrapper.rs index 705f04f73..30fd46def 100644 --- a/crates/gosub_bindings/src/wrapper.rs +++ b/crates/gosub_bindings/src/wrapper.rs @@ -1,7 +1,7 @@ pub mod node; pub mod text; -/// Numerical values that map rendertree::NodeType to C +/// Numerical values that map `rendertree::NodeType` to C #[repr(C)] pub enum CNodeType { Root = 0, diff --git a/crates/gosub_bindings/src/wrapper/node.rs b/crates/gosub_bindings/src/wrapper/node.rs index 10e35027f..4649b6833 100644 --- a/crates/gosub_bindings/src/wrapper/node.rs +++ b/crates/gosub_bindings/src/wrapper/node.rs @@ -31,10 +31,12 @@ impl Default for CNode { } impl CNode { + #[must_use] pub fn new_root() -> Self { Self::default() } + #[must_use] pub fn new_text(node: &Node, text_node: &TextNode) -> Self { Self { tag: CNodeType::Text, diff --git a/crates/gosub_bindings/src/wrapper/text.rs b/crates/gosub_bindings/src/wrapper/text.rs index 78c89312b..44705cd85 100644 --- a/crates/gosub_bindings/src/wrapper/text.rs +++ b/crates/gosub_bindings/src/wrapper/text.rs @@ -2,7 +2,7 @@ use gosub_rendering::render_tree::text::TextNode; use std::ffi::c_char; use std::ffi::CString; -/// This is a C-friendly wrapper around gosub_render_utils::rendertree::text::TextNode +/// This is a C-friendly wrapper around `gosub_render_utils::rendertree::text::TextNode` /// that converts Rust Strings to owned pointers to pass to the C API. #[repr(C)] pub struct CTextNode { diff --git a/crates/gosub_config/src/errors.rs b/crates/gosub_config/src/errors.rs index 4b4f9b93d..0f1869d4d 100644 --- a/crates/gosub_config/src/errors.rs +++ b/crates/gosub_config/src/errors.rs @@ -2,7 +2,7 @@ use thiserror::Error; /// Parser error that defines an error (message) on the given position -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ParseError { /// Parse error message pub message: String, diff --git a/crates/gosub_config/src/lib.rs b/crates/gosub_config/src/lib.rs index 40e5f9472..56b0c1804 100644 --- a/crates/gosub_config/src/lib.rs +++ b/crates/gosub_config/src/lib.rs @@ -18,7 +18,7 @@ use wildmatch::WildMatch; /// Settings are stored in a json file, but this is included in the binary for mostly easy editting. const SETTINGS_JSON: &str = include_str!("./settings.json"); -/// StoreAdapter is the interface for storing and retrieving settings +/// `StoreAdapter` is the interface for storing and retrieving settings /// This can be used to storage settings in a database, json file, etc /// Note that we need to implement Send so we can send the storage adapter /// to other threads. @@ -32,7 +32,7 @@ pub trait StorageAdapter: Send + Sync { fn set(&self, key: &str, value: Setting); /// Retrieves all the settings in the storage in one go. This is used for preloading the settings - /// into the ConfigStore and is more performant normally than calling get_setting manually for each + /// into the `ConfigStore` and is more performant normally than calling `get_setting` manually for each /// setting. fn all(&self) -> Result>; } @@ -44,7 +44,7 @@ lazy_static! { } /// Returns a reference to the config store, which is locked by a mutex. -/// Any callers of the config store can just do config::config_store().get("dns.local.enabled") +/// Any callers of the config store can just do `config::config_store().get("dns.local.enabled`") pub fn config_store() -> std::sync::RwLockReadGuard<'static, ConfigStore> { CONFIG_STORE.read().unwrap() } @@ -55,11 +55,11 @@ pub fn config_store_write() -> std::sync::RwLockWriteGuard<'static, ConfigStore> /// These macro's can be used to simplify the calls to the config store. You can simply do: /// -/// let enabled = config!(bool "dns.local.enabled").unwrap(); -/// config_set!(bool "dns.local.enabled", false); +/// let enabled = config!(bool "`dns.local.enabled").unwrap()`; +/// `config_set!(bool` "dns.local.enabled", false); /// /// Note that when you cannot find the key, it will return a default value. This is not always -/// what you want, but you can test for existence of the key with config_store().has("key") +/// what you want, but you can test for existence of the key with `config_store().has("key`") #[allow(clippy::crate_in_macro_def)] #[macro_export] macro_rules! config { @@ -115,7 +115,7 @@ macro_rules! config_set { }; } -/// JsonEntry is used for parsing the settings.json file +/// `JsonEntry` is used for parsing the settings.json file #[derive(Debug, Deserialize)] struct JsonEntry { key: String, @@ -130,7 +130,7 @@ pub struct ConfigStore { /// A hashmap of all settings so we can search o(1) time /// The mutex allows to share between multiple threads, /// The refcell allows us to use mutable references in a non-mutable way (ie: settings can be - /// stored while doing a immutable get()) + /// stored while doing a immutable `get()`) settings: std::sync::Mutex>>, /// A hashmap of all setting descriptions, default values and type information settings_info: HashMap, @@ -142,7 +142,7 @@ pub struct ConfigStore { impl Default for ConfigStore { fn default() -> Self { - let mut store = ConfigStore { + let mut store = Self { settings: std::sync::Mutex::new(std::cell::RefCell::new(HashMap::new())), settings_info: HashMap::new(), setting_keys: Vec::new(), @@ -217,7 +217,7 @@ impl ConfigStore { .unwrap() .borrow_mut() .insert(key.to_string(), setting.clone()); - return Some(setting.clone()); + return Some(setting); } // Return the default value for the setting when nothing is found @@ -227,19 +227,16 @@ impl ConfigStore { // At this point we haven't found the key in the store, we haven't found it in storage, and we // don't have a default value. This is a programming error, so we panic. - panic!("config: Setting {} is not known", key); + panic!("config: Setting {key} is not known"); } /// Sets the given setting to the given value. Will persist the setting to the /// storage. Note that the setting MUST have a settings-info entry, otherwise /// this function will not store the setting. pub fn set(&self, key: &str, value: Setting) { - let info = match self.settings_info.get(key) { - Some(info) => info, - None => { - warn!("config: Setting {key} is not known"); - return; - } + let info = if let Some(info) = self.settings_info.get(key) { info } else { + warn!("config: Setting {key} is not known"); + return; }; if mem::discriminant(&info.default) != mem::discriminant(&value) { diff --git a/crates/gosub_config/src/settings.rs b/crates/gosub_config/src/settings.rs index 56be2af6e..5b0720f48 100644 --- a/crates/gosub_config/src/settings.rs +++ b/crates/gosub_config/src/settings.rs @@ -6,7 +6,7 @@ use std::str::FromStr; /// A setting can be either a signed integer, unsigned integer, string, map or boolean. /// Maps could be created by using comma separated strings maybe -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum Setting { SInt(isize), UInt(usize), @@ -16,60 +16,64 @@ pub enum Setting { } impl Setting { + #[must_use] pub fn to_bool(&self) -> bool { - if !matches!(self, Setting::Bool(_)) { + if !matches!(self, Self::Bool(_)) { warn!("setting is not a boolean"); } match self { - Setting::Bool(value) => *value, - Setting::SInt(value) => *value != 0, - Setting::UInt(value) => *value != 0, - Setting::String(value) => is_bool_value(value), - Setting::Map(values) => !values.is_empty(), + Self::Bool(value) => *value, + Self::SInt(value) => *value != 0, + Self::UInt(value) => *value != 0, + Self::String(value) => is_bool_value(value), + Self::Map(values) => !values.is_empty(), } } + #[must_use] pub fn to_sint(&self) -> isize { - if !matches!(self, Setting::SInt(_)) { + if !matches!(self, Self::SInt(_)) { warn!("setting is not an signed integer"); } match self { - Setting::SInt(value) => *value, - Setting::UInt(value) => *value as isize, - Setting::Bool(value) => *value as isize, - Setting::String(value) => is_bool_value(value) as isize, - Setting::Map(values) => values.len() as isize, + Self::SInt(value) => *value, + Self::UInt(value) => *value as isize, + Self::Bool(value) => isize::from(*value), + Self::String(value) => isize::from(is_bool_value(value)), + Self::Map(values) => values.len() as isize, } } + #[must_use] pub fn to_uint(&self) -> usize { - if !matches!(self, Setting::UInt(_)) { + if !matches!(self, Self::UInt(_)) { warn!("setting is not an unsigned integer"); } match self { - Setting::UInt(value) => *value, - Setting::SInt(value) => *value as usize, - Setting::Bool(value) => *value as usize, - Setting::String(value) => is_bool_value(value) as usize, - Setting::Map(values) => values.len(), + Self::UInt(value) => *value, + Self::SInt(value) => *value as usize, + Self::Bool(value) => usize::from(*value), + Self::String(value) => usize::from(is_bool_value(value)), + Self::Map(values) => values.len(), } } #[allow(clippy::inherent_to_string_shadow_display)] + #[must_use] pub fn to_string(&self) -> String { - if !matches!(self, Setting::String(_)) { + if !matches!(self, Self::String(_)) { warn!("setting is not a string"); } match self { - Setting::SInt(value) => value.to_string(), - Setting::UInt(value) => value.to_string(), - Setting::String(value) => value.clone(), - Setting::Bool(value) => value.to_string(), - Setting::Map(values) => { + Self::SInt(value) => value.to_string(), + Self::UInt(value) => value.to_string(), + Self::String(value) => value.clone(), + Self::Bool(value) => value.to_string(), + Self::Map(values) => { let mut result = String::new(); for value in values { result.push_str(value); @@ -81,13 +85,14 @@ impl Setting { } } + #[must_use] pub fn to_map(&self) -> Vec { - if !matches!(self, Setting::Map(_)) { + if !matches!(self, Self::Map(_)) { warn!("setting is not a map"); } match self { - Setting::Map(values) => values.clone(), + Self::Map(values) => values.clone(), other => vec![other.to_string()], } } @@ -118,7 +123,7 @@ impl<'de> Deserialize<'de> for Setting { D: Deserializer<'de>, { let value = String::deserialize(deserializer)?; - Setting::from_str(&value) + Self::from_str(&value) .map_err(|err| serde::de::Error::custom(format!("cannot deserialize: {err}"))) } } @@ -126,11 +131,11 @@ impl<'de> Deserialize<'de> for Setting { impl Display for Setting { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Setting::SInt(value) => write!(f, "i:{value}"), - Setting::UInt(value) => write!(f, "u:{value}"), - Setting::String(value) => write!(f, "s:{value}"), - Setting::Bool(value) => write!(f, "b:{value}"), - Setting::Map(values) => { + Self::SInt(value) => write!(f, "i:{value}"), + Self::UInt(value) => write!(f, "u:{value}"), + Self::String(value) => write!(f, "s:{value}"), + Self::Bool(value) => write!(f, "b:{value}"), + Self::Map(values) => { let mut result = String::new(); for value in values { result.push_str(value); @@ -154,33 +159,33 @@ impl FromStr for Setting { // m:foo,bar,baz /// Converts a string to a setting or None when the string is invalid - fn from_str(key: &str) -> Result { + fn from_str(key: &str) -> Result { let (key_type, key_value) = key.split_once(':').expect(""); let setting = match key_type { - "b" => Setting::Bool( + "b" => Self::Bool( key_value .parse::() .map_err(|err| Error::Config(format!("error parsing {key_value}: {err}")))?, ), - "i" => Setting::SInt( + "i" => Self::SInt( key_value .parse::() .map_err(|err| Error::Config(format!("error parsing {key_value}: {err}")))?, ), - "u" => Setting::UInt( + "u" => Self::UInt( key_value .parse::() .map_err(|err| Error::Config(format!("error parsing {key_value}: {err}")))?, ), - "s" => Setting::String(key_value.to_string()), + "s" => Self::String(key_value.to_string()), "m" => { let mut values = Vec::new(); for value in key_value.split(',') { values.push(value.to_string()); } - Setting::Map(values) + Self::Map(values) } _ => return Err(Error::Config(format!("unknown setting: {key_value}"))), }; @@ -189,8 +194,8 @@ impl FromStr for Setting { } } -/// SettingInfo returns information about a given setting -#[derive(Clone, PartialEq, Debug)] +/// `SettingInfo` returns information about a given setting +#[derive(Clone, PartialEq, Eq, Debug)] pub struct SettingInfo { /// Name of the key (dot notation, (ie: dns.resolver.enabled pub key: String, @@ -214,15 +219,15 @@ mod test { assert_eq!(1, s.to_sint()); assert_eq!(1, s.to_uint()); assert_eq!("true", s.to_string()); - assert_eq!(vec!("true"), s.to_map()); + assert_eq!(vec!["true"], s.to_map()); let s = Setting::from_str("i:-1").unwrap(); assert_eq!(s, Setting::SInt(-1)); assert!(s.to_bool()); assert_eq!(-1, s.to_sint()); - assert_eq!(18446744073709551615, s.to_uint()); + assert_eq!(18_446_744_073_709_551_615, s.to_uint()); assert_eq!("-1", s.to_string()); - assert_eq!(vec!("-1"), s.to_map()); + assert_eq!(vec!["-1"], s.to_map()); let s = Setting::from_str("i:1").unwrap(); assert_eq!(s, Setting::SInt(1)); @@ -230,7 +235,7 @@ mod test { assert_eq!(1, s.to_sint()); assert_eq!(1, s.to_uint()); assert_eq!("1", s.to_string()); - assert_eq!(vec!("1"), s.to_map()); + assert_eq!(vec!["1"], s.to_map()); let s = Setting::from_str("s:hello world").unwrap(); assert_eq!(s, Setting::String("hello world".into())); @@ -238,7 +243,7 @@ mod test { assert_eq!(0, s.to_sint()); assert_eq!(0, s.to_uint()); assert_eq!("hello world", s.to_string()); - assert_eq!(vec!("hello world"), s.to_map()); + assert_eq!(vec!["hello world"], s.to_map()); let s = Setting::from_str("m:foo,bar,baz").unwrap(); assert_eq!( diff --git a/crates/gosub_config/src/storage/json.rs b/crates/gosub_config/src/storage/json.rs index be43b5e62..df4ad2b0d 100644 --- a/crates/gosub_config/src/storage/json.rs +++ b/crates/gosub_config/src/storage/json.rs @@ -35,7 +35,7 @@ impl TryFrom<&String> for JsonStorageAdapter { file }; - let mut adapter = JsonStorageAdapter { + let mut adapter = Self { path: path.to_string(), elements: Mutex::new(HashMap::new()), }; diff --git a/crates/gosub_config/src/storage/sqlite.rs b/crates/gosub_config/src/storage/sqlite.rs index 8790f6283..4dcf0189a 100644 --- a/crates/gosub_config/src/storage/sqlite.rs +++ b/crates/gosub_config/src/storage/sqlite.rs @@ -23,7 +23,7 @@ impl TryFrom<&String> for SqliteStorageAdapter { )"; conn.execute(query)?; - Ok(SqliteStorageAdapter { + Ok(Self { connection: Mutex::new(conn), }) } @@ -66,7 +66,7 @@ impl StorageAdapter for SqliteStorageAdapter { let mut statement = db_lock.prepare(query).unwrap(); let mut settings = HashMap::new(); - while let sqlite::State::Row = statement.next().unwrap() { + while statement.next().unwrap() == sqlite::State::Row { let key = statement.read::(1).unwrap(); let value = statement.read::(2).unwrap(); settings.insert(key, Setting::from_str(&value)?); diff --git a/crates/gosub_html5/src/element_class.rs b/crates/gosub_html5/src/element_class.rs index 3951e58c4..15a42061f 100644 --- a/crates/gosub_html5/src/element_class.rs +++ b/crates/gosub_html5/src/element_class.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ElementClass { /// a map of classes applied to an HTML element. - /// key = name, value = is_active - /// the is_active is used to toggle a class (JavaScript API) + /// key = name, value = `is_active` + /// the `is_active` is used to toggle a class (JavaScript API) class_map: HashMap, } @@ -15,7 +15,7 @@ impl Default for ElementClass { } impl ElementClass { - /// Initialise a new (empty) ElementClass + /// Initialise a new (empty) `ElementClass` #[must_use] pub fn new() -> Self { Self { @@ -25,16 +25,19 @@ impl ElementClass { /// Count the number of classes (active or inactive) /// assigned to an element + #[must_use] pub fn len(&self) -> usize { self.class_map.len() } /// Check if any classes are present + #[must_use] pub fn is_empty(&self) -> bool { self.class_map.is_empty() } /// Check if class name exists + #[must_use] pub fn contains(&self, name: &str) -> bool { self.class_map.contains_key(name) } @@ -70,6 +73,7 @@ impl ElementClass { } /// Check if a class is active. Returns false if class doesn't exist + #[must_use] pub fn is_active(&self, name: &str) -> bool { if let Some(is_active) = self.class_map.get(name) { return *is_active; @@ -88,7 +92,7 @@ impl From<&str> for ElementClass { .map(|class| (class.to_owned(), true)) .collect::>(); - ElementClass { + Self { class_map: class_map_local, } } diff --git a/crates/gosub_html5/src/errors.rs b/crates/gosub_html5/src/errors.rs index 5fa941a27..46dcfa435 100644 --- a/crates/gosub_html5/src/errors.rs +++ b/crates/gosub_html5/src/errors.rs @@ -3,7 +3,7 @@ use gosub_shared::byte_stream::Location; use thiserror::Error; /// Parser error that defines an error (message) on the given position -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ParseError { /// Parse error message pub message: String, diff --git a/crates/gosub_html5/src/node.rs b/crates/gosub_html5/src/node.rs index 25b0d34c7..46fc0d311 100644 --- a/crates/gosub_html5/src/node.rs +++ b/crates/gosub_html5/src/node.rs @@ -22,7 +22,7 @@ pub mod arena; pub mod data; /// Different types of nodes -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum NodeType { Document, DocType, @@ -51,14 +51,14 @@ pub enum NodeData { pub struct NodeId(pub(crate) usize); impl From for usize { - /// Converts a NodeId into a usize + /// Converts a `NodeId` into a usize fn from(value: NodeId) -> Self { value.0 } } impl From for NodeId { - /// Converts a usize into a NodeId + /// Converts a usize into a `NodeId` fn from(value: usize) -> Self { Self(value) } @@ -79,7 +79,7 @@ impl From for u64 { } impl Default for &NodeId { - /// Returns the default NodeId, which is 0 + /// Returns the default `NodeId`, which is 0 fn default() -> Self { &NodeId(0) } @@ -90,11 +90,13 @@ impl NodeId { pub const ROOT_NODE: usize = 0; /// Returns the root node ID + #[must_use] pub fn root() -> Self { Self(Self::ROOT_NODE) } /// Returns true when this nodeId is the root node + #[must_use] pub fn is_root(&self) -> bool { self.0 == Self::ROOT_NODE } @@ -110,6 +112,7 @@ impl NodeId { } /// Returns the nodeID as usize + #[must_use] pub fn as_usize(&self) -> usize { self.0 } @@ -148,13 +151,14 @@ pub struct Node { } impl Node { + #[must_use] pub fn is_root(&self) -> bool { self.id.is_root() } } impl PartialEq for Node { - fn eq(&self, other: &Node) -> bool { + fn eq(&self, other: &Self) -> bool { self.id == other.id } } @@ -183,7 +187,7 @@ impl Debug for Node { impl Clone for Node { fn clone(&self) -> Self { - Node { + Self { id: self.id, parent: self.parent, children: self.children.clone(), @@ -281,12 +285,14 @@ impl Node { } /// Returns true if the given node is a "formatting" node + #[must_use] pub fn is_formatting(&self) -> bool { self.namespace == Some(HTML_NAMESPACE.into()) && FORMATTING_HTML_ELEMENTS.contains(&self.name.as_str()) } /// Returns true if the given node is "special" node based on the namespace and name + #[must_use] pub fn is_special(&self) -> bool { if self.namespace == Some(HTML_NAMESPACE.into()) && SPECIAL_HTML_ELEMENTS.contains(&self.name.as_str()) @@ -308,6 +314,7 @@ impl Node { } /// Returns true if this node is registered into an arena + #[must_use] pub fn is_registered(&self) -> bool { self.is_registered } @@ -315,6 +322,7 @@ impl Node { /// This will only compare against the tag, namespace and data same except element data. /// for element data compaare against the tag, namespace and attributes without order. /// Both nodes could still have other parents and children. + #[must_use] pub fn matches_tag_and_attrs_without_order(&self, other: &Self) -> bool { if self.name != other.name || self.namespace != other.namespace { return false; @@ -341,6 +349,7 @@ impl Node { } /// Returns true when the given node is of the given namespace + #[must_use] pub fn is_namespace(&self, namespace: &str) -> bool { self.namespace == Some(namespace.into()) } @@ -377,6 +386,7 @@ impl Node { } /// Returns true if the node is an element node + #[must_use] pub fn is_element(&self) -> bool { if let NodeData::Element(_) = &self.data { return true; @@ -385,6 +395,7 @@ impl Node { false } + #[must_use] pub fn is_text(&self) -> bool { if let NodeData::Text(_) = &self.data { return true; @@ -393,6 +404,7 @@ impl Node { false } + #[must_use] pub fn as_text(&self) -> &TextData { if let NodeData::Text(text) = &self.data { return text; @@ -401,6 +413,7 @@ impl Node { panic!("Node is not a text"); } + #[must_use] pub fn as_element(&self) -> &ElementData { if let NodeData::Element(element) = &self.data { return element; @@ -418,6 +431,7 @@ impl Node { } /// Returns true when the given attribute has been set on the node + #[must_use] pub fn has_attribute(&self, name: &str) -> bool { if let NodeData::Element(element) = &self.data { return element.attributes.contains_key(name); @@ -427,6 +441,7 @@ impl Node { } /// Returns the given attribute value or None when the attribute is not found + #[must_use] pub fn get_attribute(&self, name: &str) -> Option<&String> { if let NodeData::Element(element) = &self.data { return element.attributes.get(name); @@ -547,7 +562,7 @@ pub static SPECIAL_HTML_ELEMENTS: [&str; 83] = [ "xmp", ]; -/// MathML elements that are considered special elements +/// `MathML` elements that are considered special elements pub static SPECIAL_MATHML_ELEMENTS: [&str; 6] = ["mi", "mo", "mn", "ms", "mtext", "annotation-xml"]; /// SVG elements that are considered special elements @@ -565,12 +580,9 @@ mod tests { assert_eq!(node.id, NodeId::default()); assert_eq!(node.parent, None); assert!(node.children.is_empty()); - assert_eq!(node.name, "".to_string()); + assert_eq!(node.name, String::new()); assert_eq!(node.namespace, None); - match &node.data { - NodeData::Document(_) => (), - _ => panic!(), - } + if let NodeData::Document(_) = &node.data {} else { panic!() } } #[test] @@ -605,7 +617,7 @@ mod tests { assert_eq!(node.id, NodeId::default()); assert_eq!(node.parent, None); assert!(node.children.is_empty()); - assert_eq!(node.name, "".to_string()); + assert_eq!(node.name, String::new()); assert_eq!(node.namespace, None); let NodeData::Comment(CommentData { value, .. }) = &node.data else { panic!() @@ -620,7 +632,7 @@ mod tests { assert_eq!(node.id, NodeId::default()); assert_eq!(node.parent, None); assert!(node.children.is_empty()); - assert_eq!(node.name, "".to_string()); + assert_eq!(node.name, String::new()); assert_eq!(node.namespace, None); let NodeData::Text(TextData { value }) = &node.data else { panic!() @@ -667,7 +679,7 @@ mod tests { #[test] fn special_html_elements() { let document = Document::shared(None); - for element in SPECIAL_HTML_ELEMENTS.iter() { + for element in &SPECIAL_HTML_ELEMENTS { let mut attributes = HashMap::new(); attributes.insert("id".to_string(), "test".to_string()); let node = Node::new_element( @@ -684,7 +696,7 @@ mod tests { #[test] fn special_mathml_elements() { let document = Document::shared(None); - for element in SPECIAL_MATHML_ELEMENTS.iter() { + for element in &SPECIAL_MATHML_ELEMENTS { let mut attributes = HashMap::new(); attributes.insert("id".to_string(), "test".to_string()); let node = Node::new_element( @@ -701,7 +713,7 @@ mod tests { #[test] fn special_svg_elements() { let document = Document::shared(None); - for element in SPECIAL_SVG_ELEMENTS.iter() { + for element in &SPECIAL_SVG_ELEMENTS { let mut attributes = HashMap::new(); attributes.insert("id".to_string(), "test".to_string()); let node = Node::new_element( diff --git a/crates/gosub_html5/src/node/arena.rs b/crates/gosub_html5/src/node/arena.rs index 2d13b58b2..e1de9b7b8 100644 --- a/crates/gosub_html5/src/node/arena.rs +++ b/crates/gosub_html5/src/node/arena.rs @@ -13,7 +13,7 @@ pub struct NodeArena { } impl NodeArena { - /// Creates a new NodeArena + /// Creates a new `NodeArena` #[must_use] pub fn new() -> Self { Self { @@ -29,12 +29,13 @@ impl NodeArena { } /// Peek what the next node ID is without incrementing the internal counter. - /// Used by DocumentTaskQueue for create_element() tasks. + /// Used by `DocumentTaskQueue` for `create_element()` tasks. pub(crate) fn peek_next_id(&self) -> NodeId { self.next_id } /// Gets the node with the given id + #[must_use] pub fn get_node(&self, node_id: NodeId) -> Option<&Node> { self.nodes.get(&node_id) } diff --git a/crates/gosub_html5/src/node/data/comment.rs b/crates/gosub_html5/src/node/data/comment.rs index 21287ecfb..2d8193828 100644 --- a/crates/gosub_html5/src/node/data/comment.rs +++ b/crates/gosub_html5/src/node/data/comment.rs @@ -1,4 +1,4 @@ -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] /// Data structure for comment nodes pub struct CommentData { /// The actual comment value @@ -25,6 +25,7 @@ impl CommentData { } } + #[must_use] pub fn value(&self) -> &str { &self.value } diff --git a/crates/gosub_html5/src/node/data/doctype.rs b/crates/gosub_html5/src/node/data/doctype.rs index 4be0bd56f..f7e1bba97 100644 --- a/crates/gosub_html5/src/node/data/doctype.rs +++ b/crates/gosub_html5/src/node/data/doctype.rs @@ -1,7 +1,7 @@ use core::fmt::{Debug, Formatter}; use std::fmt; -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Eq, Clone)] /// Data structure for document nodes pub struct DocTypeData { pub name: String, diff --git a/crates/gosub_html5/src/node/data/document.rs b/crates/gosub_html5/src/node/data/document.rs index dbaf70b68..740fada53 100644 --- a/crates/gosub_html5/src/node/data/document.rs +++ b/crates/gosub_html5/src/node/data/document.rs @@ -1,7 +1,7 @@ use core::fmt::{Debug, Formatter}; use std::fmt; -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Eq, Clone)] /// Data structure for document nodes pub struct DocumentData {} diff --git a/crates/gosub_html5/src/node/data/element.rs b/crates/gosub_html5/src/node/data/element.rs index ce64b8ece..dfe7070fb 100644 --- a/crates/gosub_html5/src/node/data/element.rs +++ b/crates/gosub_html5/src/node/data/element.rs @@ -15,7 +15,7 @@ pub struct ElementData { pub name: String, /// Element's attributes stored as key-value pairs. /// Note that it is NOT RECOMMENDED to modify this - /// attribute map directly and instead use TreeBuilder.insert_attribute + /// attribute map directly and instead use `TreeBuilder.insert_attribute` /// to keep attributes in sync with the DOM. pub attributes: HashMap, /// CSS classes @@ -67,6 +67,7 @@ impl ElementData { } } + #[must_use] pub fn name(&self) -> &str { &self.name } diff --git a/crates/gosub_html5/src/node/data/text.rs b/crates/gosub_html5/src/node/data/text.rs index d241e7cfe..77a4c8f54 100644 --- a/crates/gosub_html5/src/node/data/text.rs +++ b/crates/gosub_html5/src/node/data/text.rs @@ -1,4 +1,4 @@ -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] /// Data structure for text nodes pub struct TextData { /// Actual text @@ -25,6 +25,7 @@ impl TextData { } } + #[must_use] pub fn value(&self) -> &str { &self.value } diff --git a/crates/gosub_html5/src/parser/helper.rs b/crates/gosub_html5/src/parser/helper.rs index 2ba256ac0..248f3ce5a 100644 --- a/crates/gosub_html5/src/parser/helper.rs +++ b/crates/gosub_html5/src/parser/helper.rs @@ -250,6 +250,7 @@ impl Html5Parser<'_> { } // @todo: where is the fragment case handled? (substep 4: https://html.spec.whatwg.org/multipage/parsing.html#appropriate-place-for-inserting-a-node) + #[must_use] pub fn appropriate_place_insert( &self, override_node: Option, diff --git a/crates/gosub_html5/src/parser/query.rs b/crates/gosub_html5/src/parser/query.rs index 4036e8952..ee6d4d130 100644 --- a/crates/gosub_html5/src/parser/query.rs +++ b/crates/gosub_html5/src/parser/query.rs @@ -1,4 +1,4 @@ -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum Condition { EqualsTag(String), EqualsId(String), @@ -8,7 +8,7 @@ pub enum Condition { HasParentTag(String), } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum SearchType { Uninitialized, FindFirst, diff --git a/crates/gosub_html5/src/parser/quirks.rs b/crates/gosub_html5/src/parser/quirks.rs index 3049f1ba8..e7dfbd42c 100644 --- a/crates/gosub_html5/src/parser/quirks.rs +++ b/crates/gosub_html5/src/parser/quirks.rs @@ -1,6 +1,6 @@ use crate::parser::Html5Parser; -#[derive(PartialEq, Debug, Copy, Clone)] +#[derive(PartialEq, Eq, Debug, Copy, Clone)] pub enum QuirksMode { Quirks, LimitedQuirks, diff --git a/crates/gosub_html5/src/parser/tree_builder.rs b/crates/gosub_html5/src/parser/tree_builder.rs index d27c756f9..f9c0e58f1 100644 --- a/crates/gosub_html5/src/parser/tree_builder.rs +++ b/crates/gosub_html5/src/parser/tree_builder.rs @@ -2,10 +2,10 @@ use crate::parser::NodeId; use gosub_shared::byte_stream::Location; use gosub_shared::types::Result; -/// TreeBuilder is an interface to abstract DOM tree modifications. +/// `TreeBuilder` is an interface to abstract DOM tree modifications. /// -/// This is implemented by DocumentHandle to support direct immediate manipulation of the DOM -/// and implemented by DocumentTaskQueue to support queueing up several mutations to be performed at once. +/// This is implemented by `DocumentHandle` to support direct immediate manipulation of the DOM +/// and implemented by `DocumentTaskQueue` to support queueing up several mutations to be performed at once. pub trait TreeBuilder { /// Create a new element node with the given tag name and append it to a parent /// with an optional position parameter which places the element at a specific child index. diff --git a/crates/gosub_html5/src/tokenizer/state.rs b/crates/gosub_html5/src/tokenizer/state.rs index 6ce2c6c99..fcd611715 100644 --- a/crates/gosub_html5/src/tokenizer/state.rs +++ b/crates/gosub_html5/src/tokenizer/state.rs @@ -1,5 +1,5 @@ /// These are the states in which the tokenizer can be in. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum State { /// 8.2.4.36 After attribute name state AfterAttributeName, diff --git a/crates/gosub_html5/src/tokenizer/test_cases.rs b/crates/gosub_html5/src/tokenizer/test_cases.rs index ec4916c32..3573340e7 100644 --- a/crates/gosub_html5/src/tokenizer/test_cases.rs +++ b/crates/gosub_html5/src/tokenizer/test_cases.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unwrap_used, clippy::expect_used)] + use gosub_testing::testing::tokenizer::{self, FixtureFile}; use lazy_static::lazy_static; use std::collections::HashSet; @@ -31,7 +33,7 @@ const DISABLED_CASES: &[&str] = &[ lazy_static! { static ref DISABLED: HashSet = DISABLED_CASES .iter() - .map(|s| s.to_string()) + .map(|s| (*s).to_string()) .collect::>(); } @@ -53,8 +55,7 @@ fn tokenization(filename: &str) { let root = tokenizer::fixture_from_filename(filename).unwrap(); let tests = match root { - FixtureFile::Tests { tests } => tests, - FixtureFile::XmlTests { tests } => tests, + FixtureFile::XmlTests { tests } | FixtureFile::Tests { tests } => tests, }; for test in tests { diff --git a/crates/gosub_jsapi/Cargo.toml b/crates/gosub_jsapi/Cargo.toml index a09fae587..599571545 100644 --- a/crates/gosub_jsapi/Cargo.toml +++ b/crates/gosub_jsapi/Cargo.toml @@ -9,3 +9,7 @@ license = "MIT" gosub_shared = { path = "../gosub_shared", features = [] } uuid = { version = "1.10.0", features = ["v4"] } regex = "1" + + +[lints] +workspace = true diff --git a/crates/gosub_jsapi/src/console.rs b/crates/gosub_jsapi/src/console.rs index 7fa8c9a8a..3bffbf427 100755 --- a/crates/gosub_jsapi/src/console.rs +++ b/crates/gosub_jsapi/src/console.rs @@ -9,7 +9,7 @@ use std::fmt; use std::time::{SystemTime, UNIX_EPOCH}; use uuid::Uuid; -/// LogLevel is the type of log level. +/// `LogLevel` is the type of log level. #[derive(Debug)] pub enum LogLevel { Info, @@ -85,6 +85,7 @@ impl Console { } /// Returns the printer that is used by the console + #[must_use] pub fn get_printer(self) -> Box { self.printer } @@ -186,11 +187,11 @@ impl Console { let group_label = if data.is_empty() { format!("console.group.{}", Uuid::new_v4()) } else { - self.formatter.format(data).to_string() + self.formatter.format(data) }; let group = Group { - label: group_label.clone(), + label: group_label, }; // Group should be expanded @@ -204,11 +205,11 @@ impl Console { let group_label = if data.is_empty() { format!("console.group.{}", Uuid::new_v4()) } else { - self.formatter.format(data).to_string() + self.formatter.format(data) }; let group = Group { - label: group_label.clone(), + label: group_label, }; self.printer diff --git a/crates/gosub_jsapi/src/console/writable_printer.rs b/crates/gosub_jsapi/src/console/writable_printer.rs index 2fd30aa70..ffd76af21 100755 --- a/crates/gosub_jsapi/src/console/writable_printer.rs +++ b/crates/gosub_jsapi/src/console/writable_printer.rs @@ -12,7 +12,7 @@ pub struct Group { type Writer = Rc>; /// A writable printer that can be used to write to a buffer -pub(crate) struct WritablePrinter { +pub struct WritablePrinter { writer: Writer, groups: Vec, } diff --git a/crates/gosub_net/src/dns.rs b/crates/gosub_net/src/dns.rs index 0eb1f837a..be09aafd6 100644 --- a/crates/gosub_net/src/dns.rs +++ b/crates/gosub_net/src/dns.rs @@ -12,7 +12,7 @@ use std::net::IpAddr; use std::time::{SystemTime, UNIX_EPOCH}; /// A DNS entry is a mapping of a domain to zero or more IP address mapping -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct DnsEntry { // domain name domain: String, @@ -57,6 +57,7 @@ impl DnsEntry { } /// Returns true if the dns entry has expired + #[must_use] pub fn expired(&self) -> bool { self.expires < SystemTime::now() @@ -82,7 +83,7 @@ impl DnsEntry { } /// Type of DNS resolution -#[derive(Clone, Debug, Display, PartialEq)] +#[derive(Clone, Debug, Display, PartialEq, Eq)] pub enum ResolveType { /// Only resolve IPV4 addresses (A) Ipv4, @@ -93,7 +94,7 @@ pub enum ResolveType { } trait DnsResolver { - /// Resolves a domain name for a given resolver_type + /// Resolves a domain name for a given `resolver_type` fn resolve(&mut self, domain: &str, resolve_type: ResolveType) -> Result; /// Announces the resolved dns entry for the domain to a resolver fn announce(&mut self, _domain: &str, _entry: &DnsEntry) {} @@ -147,7 +148,7 @@ impl Dns { Self { resolvers } } - /// Resolves a domain name to a set of IP addresses based on the resolve_type. + /// Resolves a domain name to a set of IP addresses based on the `resolve_type`. /// It can resolve either Ipv4, ipv6 or both addresses. /// /// Each request will be resolved by the resolvers in the order they are added. @@ -179,7 +180,7 @@ impl Dns { resolver.announce(domain, &entry.clone().unwrap().clone()); } - Ok(entry.unwrap().clone()) + Ok(entry.unwrap()) } } @@ -199,26 +200,26 @@ mod test { let now = Instant::now(); let e = dns.resolve("example.org", ResolveType::Ipv4).unwrap(); let elapsed_time = now.elapsed(); - e.ipv4().iter().for_each(|x| println!("ipv4: {}", x)); + e.ipv4().iter().for_each(|x| println!("ipv4: {x}")); println!("Took {} microseconds.", elapsed_time.as_micros()); let now = Instant::now(); let e = dns.resolve("example.org", ResolveType::Ipv6).unwrap(); let elapsed_time = now.elapsed(); - e.ipv6().iter().for_each(|x| println!("ipv6: {}", x)); + e.ipv6().iter().for_each(|x| println!("ipv6: {x}")); println!("Took {} microseconds.", elapsed_time.as_micros()); let now = Instant::now(); let e = dns.resolve("example.org", ResolveType::Ipv4).unwrap(); let elapsed_time = now.elapsed(); - e.ipv4().iter().for_each(|x| println!("ipv4: {}", x)); + e.ipv4().iter().for_each(|x| println!("ipv4: {x}")); println!("Took {} microseconds.", elapsed_time.as_micros()); let now = Instant::now(); let e = dns.resolve("example.org", ResolveType::Both).unwrap(); let elapsed_time = now.elapsed(); - e.ipv4().iter().for_each(|x| println!("ipv4: {}", x)); - e.ipv6().iter().for_each(|x| println!("ipv6: {}", x)); + e.ipv4().iter().for_each(|x| println!("ipv4: {x}")); + e.ipv6().iter().for_each(|x| println!("ipv6: {x}")); println!("Took {} microseconds.", elapsed_time.as_micros()); } } diff --git a/crates/gosub_net/src/dns/cache.rs b/crates/gosub_net/src/dns/cache.rs index 050cab856..cb5248120 100644 --- a/crates/gosub_net/src/dns/cache.rs +++ b/crates/gosub_net/src/dns/cache.rs @@ -4,7 +4,7 @@ use gosub_shared::types::Result; use log::trace; use std::collections::{HashMap, VecDeque}; -pub(crate) struct CacheResolver { +pub struct CacheResolver { values: HashMap, max_entries: usize, lru: VecDeque, @@ -91,8 +91,8 @@ impl DnsCache for CacheResolver { } impl CacheResolver { - pub(crate) fn new(max_entries: usize) -> CacheResolver { - CacheResolver { + pub(crate) fn new(max_entries: usize) -> Self { + Self { values: HashMap::with_capacity(max_entries), max_entries, lru: VecDeque::with_capacity(max_entries), diff --git a/crates/gosub_net/src/http/request.rs b/crates/gosub_net/src/http/request.rs index b25ac4b72..10a2695af 100644 --- a/crates/gosub_net/src/http/request.rs +++ b/crates/gosub_net/src/http/request.rs @@ -12,6 +12,7 @@ pub struct Request { } impl Request { + #[must_use] pub fn new(method: &str, uri: &str, version: &str) -> Self { Self { method: method.to_string(), @@ -37,13 +38,13 @@ impl Display for Request { writeln!(f, "{} {} {}", self.method, self.uri, self.version)?; writeln!(f, "Headers:")?; for (key, value) in self.headers.sorted() { - writeln!(f, " {}: {}", key, value)?; + writeln!(f, " {key}: {value}")?; } writeln!(f, "Cookies:")?; let mut sorted_cookies = self.cookies.iter().collect::>(); sorted_cookies.sort_by(|a, b| a.name().cmp(b.name())); for cookie in sorted_cookies { - writeln!(f, " {}", cookie)?; + writeln!(f, " {cookie}")?; } writeln!(f, "Body: {} bytes", self.body.len())?; @@ -87,7 +88,7 @@ mod tests { req.headers.set_str("Accept", "text/html"); req.headers.set_str("Accept-Encoding", "gzip, deflate, br"); - let s = format!("{}", req); + let s = format!("{req}"); assert_eq!(s, "GET / HTTP/1.1\nHeaders:\n Accept: text/html\n Accept-Encoding: gzip, deflate, br\n Content-Type: application/json\nCookies:\n foo=bar\n qux=wok\nBody: 0 bytes\n"); } } diff --git a/crates/gosub_net/src/http/response.rs b/crates/gosub_net/src/http/response.rs index ac30620a7..4ad99372e 100644 --- a/crates/gosub_net/src/http/response.rs +++ b/crates/gosub_net/src/http/response.rs @@ -14,10 +14,11 @@ pub struct Response { } impl Response { - pub fn new() -> Response { + #[must_use] + pub fn new() -> Self { Self { status: 0, - status_text: "".to_string(), + status_text: String::new(), version: "HTTP/1.1".to_string(), headers: Default::default(), cookies: Default::default(), @@ -94,11 +95,11 @@ impl Display for Response { writeln!(f, "HTTP/1.1 {}", self.status)?; writeln!(f, "Headers:")?; for (key, value) in self.headers.all() { - writeln!(f, " {}: {}", key, value)?; + writeln!(f, " {key}: {value}")?; } writeln!(f, "Cookies:")?; for (key, value) in &self.cookies { - writeln!(f, " {}: {}", key, value)?; + writeln!(f, " {key}: {value}")?; } writeln!(f, "Body: {} bytes", self.body.len())?; @@ -114,7 +115,7 @@ mod tests { fn response() { let mut response = Response::new(); - let s = format!("{}", response); + let s = format!("{response}"); assert_eq!(s, "HTTP/1.1 0\nHeaders:\nCookies:\nBody: 0 bytes\n"); response.status = 200; @@ -124,7 +125,7 @@ mod tests { .insert("session".to_string(), "1234567890".to_string()); response.body = b"Hello, world!".to_vec(); - let s = format!("{}", response); + let s = format!("{response}"); assert_eq!(s, "HTTP/1.1 200\nHeaders:\n Content-Type: application/json\nCookies:\n session: 1234567890\nBody: 13 bytes\n"); } } diff --git a/crates/gosub_render_utils/Cargo.toml b/crates/gosub_render_utils/Cargo.toml index 2cf2ef8eb..4b620e84a 100644 --- a/crates/gosub_render_utils/Cargo.toml +++ b/crates/gosub_render_utils/Cargo.toml @@ -13,3 +13,8 @@ gosub_render_backend = { path = "../gosub_render_backend" } anyhow = "1.0.86" regex = "1.10.6" rstar = "0.12.0" + + + +[lints] +workspace = true diff --git a/crates/gosub_render_utils/src/render_tree.rs b/crates/gosub_render_utils/src/render_tree.rs index 4116970e0..34f792cbf 100644 --- a/crates/gosub_render_utils/src/render_tree.rs +++ b/crates/gosub_render_utils/src/render_tree.rs @@ -12,7 +12,7 @@ pub mod properties; pub mod text; pub mod util; -/// A RenderTree is a data structure to be consumed by a user agent +/// A `RenderTree` is a data structure to be consumed by a user agent /// that combines the DOM and CSSOM to compute layouts and styles /// for objects to draw on the screen. pub struct RenderTree { @@ -81,10 +81,10 @@ impl RenderTree { } } -/// An individual node that sits inside a RenderTree. -/// A RenderTree Node mimics a Node from the DOM but +/// An individual node that sits inside a `RenderTree`. +/// A `RenderTree` Node mimics a Node from the DOM but /// contains more visual information such as width, -/// height, font sizes, colors, etc. A RenderTree Node +/// height, font sizes, colors, etc. A `RenderTree` Node /// can have children just like regular DOM nodes. #[derive(Debug, PartialEq)] #[repr(C)] @@ -138,52 +138,52 @@ impl Node { let margin = 10.72; let heading = TextNode::new_heading1(); - Node::new_text(heading, margin, position) + Self::new_text(heading, margin, position) } pub fn new_heading2(position: &mut Position) -> Self { let margin = 9.96; let heading = TextNode::new_heading2(); - Node::new_text(heading, margin, position) + Self::new_text(heading, margin, position) } pub fn new_heading3(position: &mut Position) -> Self { let margin = 9.36; let heading = TextNode::new_heading3(); - Node::new_text(heading, margin, position) + Self::new_text(heading, margin, position) } pub fn new_heading4(position: &mut Position) -> Self { let margin = 10.64; let heading = TextNode::new_heading4(); - Node::new_text(heading, margin, position) + Self::new_text(heading, margin, position) } pub fn new_heading5(position: &mut Position) -> Self { let margin = 11.089; let heading = TextNode::new_heading5(); - Node::new_text(heading, margin, position) + Self::new_text(heading, margin, position) } pub fn new_heading6(position: &mut Position) -> Self { let margin = 12.489; let heading = TextNode::new_heading6(); - Node::new_text(heading, margin, position) + Self::new_text(heading, margin, position) } pub fn new_paragraph(position: &mut Position) -> Self { let margin = 8.; let paragraph = TextNode::new_paragraph(); - Node::new_text(paragraph, margin, position) + Self::new_text(paragraph, margin, position) } - pub fn add_child(&mut self, child: &Rc>) { + pub fn add_child(&mut self, child: &Rc>) { if let Some(last_child) = &self.children.last().borrow_mut() { last_child.as_ref().borrow_mut().next_sibling = Some(Rc::clone(child)); } @@ -197,7 +197,7 @@ impl Default for Node { } } -/// Different types of RenderTree Nodes +/// Different types of `RenderTree` Nodes // NOTE: tag size must be u32 otherwise it wont work with a C enum (originally I tried u8) #[derive(Debug, PartialEq)] #[repr(C, u32)] @@ -210,7 +210,7 @@ pub enum NodeType { // TODO: add more types as we build out the RenderTree } -/// Constructs an iterator for a RenderTree +/// Constructs an iterator for a `RenderTree` pub struct TreeIterator { current_node: Option>>, node_stack: Vec>>, @@ -225,6 +225,7 @@ impl TreeIterator { } } + #[must_use] pub fn current(&self) -> Option>> { if let Some(node) = &self.current_node { return Some(Rc::clone(node)); diff --git a/crates/gosub_render_utils/src/render_tree/properties.rs b/crates/gosub_render_utils/src/render_tree/properties.rs index b7ffc601c..31661756a 100644 --- a/crates/gosub_render_utils/src/render_tree/properties.rs +++ b/crates/gosub_render_utils/src/render_tree/properties.rs @@ -25,6 +25,7 @@ impl Rectangle { } } + #[must_use] pub fn with_values(top: f64, left: f64, right: f64, bottom: f64) -> Self { Self { top, @@ -50,7 +51,8 @@ impl Position { Self { x: 0., y: 0. } } - pub fn new_from_existing(position: &Position) -> Self { + #[must_use] + pub fn new_from_existing(position: &Self) -> Self { Self { x: position.x, y: position.y, @@ -64,21 +66,21 @@ impl Position { } /// Move position relative to another position. - /// x = relative.x + x_offset - /// y = relative.y + y_offset - pub fn move_relative_to(&mut self, relative_position: &Position, x_offset: f64, y_offset: f64) { + /// x = relative.x + `x_offset` + /// y = relative.y + `y_offset` + pub fn move_relative_to(&mut self, relative_position: &Self, x_offset: f64, y_offset: f64) { self.x = relative_position.x + x_offset; self.y = relative_position.y + y_offset; } /// Adjust y by an offset. - /// y += offset_y + /// y += `offset_y` pub fn offset_y(&mut self, offset_y: f64) { self.y += offset_y; } /// Adjust x by an offset. - /// x += offset_x + /// x += `offset_x` pub fn offset_x(&mut self, offset_x: f64) { self.x += offset_x; } diff --git a/crates/gosub_render_utils/src/render_tree/text.rs b/crates/gosub_render_utils/src/render_tree/text.rs index d83e79ce4..101ccb823 100644 --- a/crates/gosub_render_utils/src/render_tree/text.rs +++ b/crates/gosub_render_utils/src/render_tree/text.rs @@ -13,38 +13,45 @@ impl TextNode { #[must_use] fn new(fs: f64, bold: bool) -> Self { Self { - value: "".to_owned(), + value: String::new(), font: "Times New Roman".to_owned(), font_size: fs, is_bold: bold, } } + #[must_use] pub fn new_heading1() -> Self { - TextNode::new(37., true) + Self::new(37., true) } + #[must_use] pub fn new_heading2() -> Self { - TextNode::new(27.5, true) + Self::new(27.5, true) } + #[must_use] pub fn new_heading3() -> Self { - TextNode::new(21.5, true) + Self::new(21.5, true) } + #[must_use] pub fn new_heading4() -> Self { - TextNode::new(18.5, true) + Self::new(18.5, true) } + #[must_use] pub fn new_heading5() -> Self { - TextNode::new(15.5, true) + Self::new(15.5, true) } + #[must_use] pub fn new_heading6() -> Self { - TextNode::new(12., true) + Self::new(12., true) } + #[must_use] pub fn new_paragraph() -> Self { - TextNode::new(18.5, false) + Self::new(18.5, false) } } diff --git a/crates/gosub_shared/Cargo.toml b/crates/gosub_shared/Cargo.toml index 1da88317b..8864725de 100644 --- a/crates/gosub_shared/Cargo.toml +++ b/crates/gosub_shared/Cargo.toml @@ -23,4 +23,9 @@ getrandom = { version = "0.2.15", features = ["js"] } web-sys = { version = "0.3.69", features = ["Performance", "Window"] } [dev-dependencies] -wasm-bindgen-test = "0.3.20" \ No newline at end of file +wasm-bindgen-test = "0.3.20" + + + +[lints] +workspace = true diff --git a/crates/gosub_shared/src/timing.rs b/crates/gosub_shared/src/timing.rs index 4aff52c1e..8067ca1c9 100644 --- a/crates/gosub_shared/src/timing.rs +++ b/crates/gosub_shared/src/timing.rs @@ -58,8 +58,9 @@ fn percentage_to_index(count: u64, percentage: f64) -> usize { } impl TimingTable { - pub fn new() -> TimingTable { - TimingTable { + #[must_use] + pub fn new() -> Self { + Self { timers: HashMap::new(), namespaces: HashMap::new(), } @@ -82,6 +83,7 @@ impl TimingTable { } } + #[must_use] pub fn get_stats(&self, timers: &Vec) -> Stats { let mut durations: Vec = Vec::new(); @@ -94,7 +96,7 @@ impl TimingTable { } } - durations.sort(); + durations.sort_unstable(); let count = durations.len() as u64; let total = durations.iter().sum(); let min = *durations.first().unwrap_or(&0); @@ -120,12 +122,12 @@ impl TimingTable { fn scale(&self, value: u64, scale: Scale) -> String { match scale { - Scale::MicroSecond => format!("{}µs", value), + Scale::MicroSecond => format!("{value}µs"), Scale::MilliSecond => format!("{}ms", value / 1000), Scale::Second => format!("{}s", value / (1000 * 1000)), Scale::Auto => { if value < 1000 { - format!("{}µs", value) + format!("{value}µs") } else if value < 1000 * 1000 { format!("{}ms", value / 1000) } else { @@ -160,7 +162,7 @@ impl TimingTable { " | {:>8} | {:>10} | {}", 1, self.scale(timer.duration_us, scale.clone()), - timer.context.clone().unwrap_or("".into()) + timer.context.clone().unwrap_or_default() ); } } @@ -168,6 +170,7 @@ impl TimingTable { } } + #[must_use] pub fn duration(&self, timer_id: TimerId) -> u64 { if let Some(timer) = self.timers.get(&timer_id) { timer.duration() @@ -251,7 +254,8 @@ pub struct Timer { } impl Timer { - pub fn new(context: Option) -> Timer { + #[must_use] + pub fn new(context: Option) -> Self { #[cfg(not(target_arch = "wasm32"))] let start = { Instant::now() }; @@ -263,7 +267,7 @@ impl Timer { .unwrap_or(f64::NAN) }; - Timer { + Self { id: new_timer_id(), context, start, @@ -304,6 +308,7 @@ impl Timer { self.end.is_some() } + #[must_use] pub fn duration(&self) -> u64 { if self.end.is_some() { self.duration_us diff --git a/crates/gosub_shared/src/types.rs b/crates/gosub_shared/src/types.rs index c6fb88afa..1bc8a37b5 100644 --- a/crates/gosub_shared/src/types.rs +++ b/crates/gosub_shared/src/types.rs @@ -5,7 +5,7 @@ use std::ops::Add; use thiserror::Error; /// Parser error that defines an error (message) on the given position -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ParseError { /// Parse error message pub message: String, diff --git a/crates/gosub_testing/Cargo.toml b/crates/gosub_testing/Cargo.toml index 644411f14..d6f0c3836 100644 --- a/crates/gosub_testing/Cargo.toml +++ b/crates/gosub_testing/Cargo.toml @@ -14,4 +14,9 @@ serde_derive = "1.0" lazy_static = "1.5" nom = "7.1.3" nom_locate = "4.2.0" -regex = "1" \ No newline at end of file +regex = "1" + + + +[lints] +workspace = true diff --git a/crates/gosub_testing/src/testing/tree_construction.rs b/crates/gosub_testing/src/testing/tree_construction.rs index 693c3c563..2931e5cf2 100644 --- a/crates/gosub_testing/src/testing/tree_construction.rs +++ b/crates/gosub_testing/src/testing/tree_construction.rs @@ -31,6 +31,7 @@ pub struct Test { impl Test { /// Returns the script modes that should be tested as an array + #[must_use] pub fn script_modes(&self) -> &[bool] { match self.spec.script_mode { ScriptMode::ScriptOff => &[false], @@ -39,10 +40,12 @@ impl Test { } } + #[must_use] pub fn document_as_str(&self) -> &str { self.spec.document.as_str() } + #[must_use] pub fn spec_data(&self) -> &str { self.spec.data.as_str() } @@ -64,7 +67,7 @@ impl Default for Harness { } impl Harness { - /// Generated a new harness instance. It uses a dummy test that is replaced when run_test is called + /// Generated a new harness instance. It uses a dummy test that is replaced when `run_test` is called #[must_use] pub fn new() -> Self { Self { diff --git a/crates/gosub_testing/src/testing/tree_construction/fixture.rs b/crates/gosub_testing/src/testing/tree_construction/fixture.rs index a8b751567..09dedc82d 100644 --- a/crates/gosub_testing/src/testing/tree_construction/fixture.rs +++ b/crates/gosub_testing/src/testing/tree_construction/fixture.rs @@ -48,6 +48,7 @@ fn use_fixture(filenames: &[&str], path: impl AsRef) -> bool { } /// Returns the root path for the fixtures +#[must_use] pub fn fixture_root_path() -> PathBuf { PathBuf::from(FIXTURE_ROOT).join(TREE_CONSTRUCTION_PATH) } @@ -80,7 +81,7 @@ fn create_document_array(s: &str) -> Vec { .replace(QUOTED_DOUBLE_NEWLINE, "\"\n\n\"") .split('|') .skip(1) - .flat_map(|l| (!l.is_empty()).then(|| format!("|{}", l.trim_end()))) + .filter_map(|l| (!l.is_empty()).then(|| format!("|{}", l.trim_end()))) .collect::>(); document diff --git a/crates/gosub_testing/src/testing/tree_construction/parser.rs b/crates/gosub_testing/src/testing/tree_construction/parser.rs index 49a7de3e7..a994997b8 100644 --- a/crates/gosub_testing/src/testing/tree_construction/parser.rs +++ b/crates/gosub_testing/src/testing/tree_construction/parser.rs @@ -15,13 +15,13 @@ pub const QUOTED_DOUBLE_NEWLINE: &str = ":quoted-double-newline:"; type Span<'a> = LocatedSpan<&'a str>; -#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct Position { pub line: usize, pub col: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum ErrorSpec { Message(String), @@ -42,7 +42,7 @@ pub enum ErrorSpec { }, } -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub enum ScriptMode { ScriptOn, ScriptOff, @@ -244,7 +244,7 @@ fn old_errors(i: Span) -> IResult> { )), error_messages, ))), - |errors| errors.unwrap_or_default(), + std::option::Option::unwrap_or_default, ), multispace0, )(i) @@ -319,7 +319,7 @@ fn trim_last_newline(s: String) -> String { pub fn parse_fixture(i: &str) -> Result> { // Deal with a corner case that makes it hard to parse tricky01.dat. - let input = i.replace("\"\n\n\"", QUOTED_DOUBLE_NEWLINE).clone() + "\n"; + let input = i.replace("\"\n\n\"", QUOTED_DOUBLE_NEWLINE) + "\n"; let files = map( tuple((separated_list1(tag("\n\n"), test), multispace0)), @@ -359,7 +359,7 @@ mod tests { assert_eq!( *s, "

\n" - ) + ); } #[test] @@ -516,7 +516,7 @@ FOO