diff --git a/contrib/dyn_templates/Cargo.toml b/contrib/dyn_templates/Cargo.toml index f7f450ba..2fffd097 100644 --- a/contrib/dyn_templates/Cargo.toml +++ b/contrib/dyn_templates/Cargo.toml @@ -12,6 +12,10 @@ license = "MIT OR Apache-2.0" edition = "2021" rust-version = "1.75" +[lints.clippy] +type_complexity = "allow" +multiple_bound_locations = "allow" + [features] tera = ["tera_"] handlebars = ["handlebars_"] diff --git a/contrib/dyn_templates/src/context.rs b/contrib/dyn_templates/src/context.rs index ecdd9321..344348ad 100644 --- a/contrib/dyn_templates/src/context.rs +++ b/contrib/dyn_templates/src/context.rs @@ -84,7 +84,7 @@ impl Context { if !templates.contains_key(name) { let data_type = Path::new(name).extension() .and_then(|osstr| osstr.to_str()) - .and_then(|ext| ContentType::from_extension(ext)) + .and_then(ContentType::from_extension) .unwrap_or(ContentType::Text); let info = TemplateInfo { path: None, engine_ext, data_type }; @@ -183,7 +183,7 @@ mod manager { if let Some(true) = templates_changes { info_!("Change detected: reloading templates."); let root = self.context().root.clone(); - if let Some(new_ctxt) = Context::initialize(&root, &callback) { + if let Some(new_ctxt) = Context::initialize(&root, callback) { *self.context_mut() = new_ctxt; } else { warn_!("An error occurred while reloading templates."); @@ -217,7 +217,7 @@ fn split_path(root: &Path, path: &Path) -> (String, Option) { // Ensure template name consistency on Windows systems if cfg!(windows) { - name = name.replace("\\", "/"); + name = name.replace('\\', "/"); } (name, data_type.map(|d| d.to_string_lossy().into_owned())) diff --git a/contrib/dyn_templates/src/handlebars_templates.rs b/contrib/dyn_templates/src/handlebars_templates.rs index 82a13022..39b6dffa 100644 --- a/contrib/dyn_templates/src/handlebars_templates.rs +++ b/contrib/dyn_templates/src/handlebars_templates.rs @@ -20,7 +20,7 @@ impl Engine for Handlebars<'static> { } } - ok.then(|| hb) + ok.then_some(hb) } fn render(&self, name: &str, context: C) -> Option { diff --git a/contrib/dyn_templates/src/lib.rs b/contrib/dyn_templates/src/lib.rs index d239005c..8363f870 100644 --- a/contrib/dyn_templates/src/lib.rs +++ b/contrib/dyn_templates/src/lib.rs @@ -412,7 +412,7 @@ impl Template { Status::InternalServerError })?; - let string = ctxt.engines.render(name, &info, value).ok_or_else(|| { + let string = ctxt.engines.render(name, info, value).ok_or_else(|| { error_!("Template '{}' failed to render.", name); Status::InternalServerError })?; diff --git a/contrib/ws/src/websocket.rs b/contrib/ws/src/websocket.rs index 662cbe65..78ec77d6 100644 --- a/contrib/ws/src/websocket.rs +++ b/contrib/ws/src/websocket.rs @@ -109,8 +109,8 @@ impl WebSocket { /// })) /// } /// ``` - pub fn channel<'r, F: Send + 'r>(self, handler: F) -> Channel<'r> - where F: FnOnce(DuplexStream) -> BoxFuture<'r, Result<()>> + 'r + pub fn channel<'r, F>(self, handler: F) -> Channel<'r> + where F: FnOnce(DuplexStream) -> BoxFuture<'r, Result<()>> + Send + 'r { Channel { ws: self, handler: Box::new(handler), } } diff --git a/core/codegen/Cargo.toml b/core/codegen/Cargo.toml index 0f3b051d..5010690a 100644 --- a/core/codegen/Cargo.toml +++ b/core/codegen/Cargo.toml @@ -15,6 +15,10 @@ rust-version = "1.75" [lib] proc-macro = true +[lints.clippy] +manual_range_contains = "allow" +large_enum_variant = "allow" + [dependencies] indexmap = "2" quote = "1.0" diff --git a/core/codegen/src/attribute/async_bound/mod.rs b/core/codegen/src/attribute/async_bound/mod.rs index 728f199a..9e4d1d1c 100644 --- a/core/codegen/src/attribute/async_bound/mod.rs +++ b/core/codegen/src/attribute/async_bound/mod.rs @@ -16,7 +16,7 @@ fn _async_bound( let mut func: TraitItemFn = syn::parse(input)?; let original: TraitItemFn = func.clone(); - if !func.sig.asyncness.is_some() { + if func.sig.asyncness.is_none() { let diag = Span::call_site() .error("attribute can only be applied to async fns") .span_help(func.sig.span(), "this fn declaration must be `async`"); diff --git a/core/codegen/src/attribute/param/parse.rs b/core/codegen/src/attribute/param/parse.rs index e542cd41..c334034e 100644 --- a/core/codegen/src/attribute/param/parse.rs +++ b/core/codegen/src/attribute/param/parse.rs @@ -31,7 +31,7 @@ impl Dynamic { segment: &str, span: Span, ) -> Result> { - match Parameter::parse::

(&segment, span)? { + match Parameter::parse::

(segment, span)? { Parameter::Dynamic(d) | Parameter::Ignored(d) => Ok(d), Parameter::Guard(g) => Ok(g.source), Parameter::Static(_) => Err(Error::new(segment, span, ErrorKind::Static)), diff --git a/core/codegen/src/attribute/route/mod.rs b/core/codegen/src/attribute/route/mod.rs index dbf28a51..6b9ffb1c 100644 --- a/core/codegen/src/attribute/route/mod.rs +++ b/core/codegen/src/attribute/route/mod.rs @@ -293,7 +293,7 @@ fn sentinels_expr(route: &Route) -> TokenStream { let eligible_types = route.guards() .map(|guard| &guard.ty) - .chain(ret_ty.as_ref().into_iter()) + .chain(ret_ty.as_ref()) .flat_map(|ty| ty.unfold_with_ty_macros(TY_MACS, ty_mac_mapper)) .filter(|ty| ty.is_concrete(&generic_idents)) .map(|child| (child.parent, child.ty)); diff --git a/core/codegen/src/attribute/route/parse.rs b/core/codegen/src/attribute/route/parse.rs index 59cbd4e3..3918114d 100644 --- a/core/codegen/src/attribute/route/parse.rs +++ b/core/codegen/src/attribute/route/parse.rs @@ -180,7 +180,7 @@ impl Route { // Collect all of the declared dynamic route parameters. let all_dyn_params = path_params.iter().filter_map(|p| p.dynamic()) .chain(query_params.iter().filter_map(|p| p.dynamic())) - .chain(data_guard.as_ref().map(|g| &g.source).into_iter()); + .chain(data_guard.as_ref().map(|g| &g.source)); // Check for any duplicates in the dynamic route parameters. let mut dyn_params: IndexSet<&Dynamic> = IndexSet::new(); @@ -196,7 +196,7 @@ impl Route { .filter(|(name, _)| { let mut all_other_guards = path_params.iter().filter_map(|p| p.guard()) .chain(query_params.iter().filter_map(|p| p.guard())) - .chain(data_guard.as_ref().into_iter()); + .chain(data_guard.as_ref()); all_other_guards.all(|g| &g.name != *name) }) diff --git a/core/codegen/src/bang/mod.rs b/core/codegen/src/bang/mod.rs index d27358eb..714a19d6 100644 --- a/core/codegen/src/bang/mod.rs +++ b/core/codegen/src/bang/mod.rs @@ -47,19 +47,19 @@ pub fn catchers_macro(input: proc_macro::TokenStream) -> TokenStream { pub fn uri_macro(input: proc_macro::TokenStream) -> TokenStream { uri::_uri_macro(input.into()) .unwrap_or_else(|diag| diag.emit_as_expr_tokens_or(quote! { - rocket::http::uri::Origin::ROOT + rocket::http::uri::Origin::root() })) } pub fn uri_internal_macro(input: proc_macro::TokenStream) -> TokenStream { - // TODO: Ideally we would generate a perfect `Origin::ROOT` so that we don't + // TODO: Ideally we would generate a perfect `Origin::root()` so that we don't // assist in propagating further errors. Alas, we can't set the span to the // invocation of `uri!` without access to `span.parent()`, and // `Span::call_site()` here points to the `#[route]`, immediate caller, // generating a rather confusing error message when there's a type-mismatch. uri::_uri_internal_macro(input.into()) .unwrap_or_else(|diag| diag.emit_as_expr_tokens_or(quote! { - rocket::http::uri::Origin::ROOT + rocket::http::uri::Origin::root() })) } diff --git a/core/codegen/src/bang/test_guide.rs b/core/codegen/src/bang/test_guide.rs index cfbfc124..a664ac25 100644 --- a/core/codegen/src/bang/test_guide.rs +++ b/core/codegen/src/bang/test_guide.rs @@ -15,10 +15,10 @@ pub fn _macro(input: proc_macro::TokenStream) -> devise::Result { fn entry_to_tests(root_glob: &LitStr) -> Result, Box> { let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("MANIFEST_DIR"); - let full_glob = Path::new(&manifest_dir).join(&root_glob.value()).display().to_string(); + let full_glob = Path::new(&manifest_dir).join(root_glob.value()); let mut tests = vec![]; - for path in glob::glob(&full_glob).map_err(Box::new)? { + for path in glob::glob(&full_glob.to_string_lossy()).map_err(Box::new)? { let path = path.map_err(Box::new)?; let name = path.file_name() .and_then(|f| f.to_str()) @@ -38,7 +38,7 @@ fn entry_to_tests(root_glob: &LitStr) -> Result, Box } if tests.is_empty() { - return Err(format!("glob '{}' evaluates to 0 files", full_glob).into()); + return Err(format!("glob '{}' evaluates to 0 files", full_glob.display()).into()); } Ok(tests) diff --git a/core/codegen/src/bang/uri.rs b/core/codegen/src/bang/uri.rs index b8e6c1d4..12f40cea 100644 --- a/core/codegen/src/bang/uri.rs +++ b/core/codegen/src/bang/uri.rs @@ -151,7 +151,7 @@ fn explode_path<'a>( Parameter::Dynamic(_) | Parameter::Guard(_) => { let (ident, ty) = args.next().expect("ident/ty for non-ignored"); let expr = exprs.next().expect("one expr per dynamic arg"); - add_binding::(bindings, &ident, &ty, &expr); + add_binding::(bindings, ident, ty, expr); quote_spanned!(expr.span() => &#ident as &dyn #uri_display) } Parameter::Ignored(_) => { @@ -207,7 +207,7 @@ fn explode_query<'a>( }; let name = &dynamic.name; - add_binding::(bindings, &ident, &ty, &expr); + add_binding::(bindings, ident, ty, expr); Some(match dynamic.trailing { false => quote_spanned! { expr.span() => #query_arg::NameValue(#name, &#ident as &dyn #uri_display) diff --git a/core/codegen/src/bang/uri_parsing.rs b/core/codegen/src/bang/uri_parsing.rs index efbe41a2..a05e7f55 100644 --- a/core/codegen/src/bang/uri_parsing.rs +++ b/core/codegen/src/bang/uri_parsing.rs @@ -421,10 +421,7 @@ impl RoutedUri { impl Arg { fn is_named(&self) -> bool { - match *self { - Arg::Named(..) => true, - _ => false - } + matches!(self, Arg::Named(..)) } fn unnamed(&self) -> &ArgExpr { @@ -484,7 +481,7 @@ impl UriExpr { let lit = input.parse::()?; let uri = Uri::parse::>(&lit) .or_else(|e| Uri::parse::>(&lit).map_err(|e2| (e, e2))) - .map_err(|(e1, e2)| lit.starts_with('/').then(|| e1).unwrap_or(e2)) + .map_err(|(e1, e2)| if lit.starts_with('/') { e1 } else { e2 }) .or_else(|e| uri_err(&lit, e))?; if matches!(&uri, Uri::Origin(o) if o.query().is_some()) diff --git a/core/codegen/src/derive/form_field.rs b/core/codegen/src/derive/form_field.rs index 737673d6..60688e5e 100644 --- a/core/codegen/src/derive/form_field.rs +++ b/core/codegen/src/derive/form_field.rs @@ -327,7 +327,7 @@ impl VisitMut for ValidationMutator<'_> { *i = expr; } - } else if let Some(expr) = inner_field(&i) { + } else if let Some(expr) = inner_field(i) { *i = expr; } @@ -335,7 +335,7 @@ impl VisitMut for ValidationMutator<'_> { } } -pub fn validators<'v>(field: Field<'v>) -> Result + 'v> { +pub fn validators(field: Field<'_>) -> Result + '_> { Ok(FieldAttr::from_attrs(FieldAttr::NAME, &field.attrs)? .into_iter() .chain(FieldAttr::from_attrs(FieldAttr::NAME, field.parent.attrs())?) @@ -396,7 +396,7 @@ fn default_expr(expr: &syn::Expr) -> TokenStream { } } -pub fn default<'v>(field: Field<'v>) -> Result> { +pub fn default(field: Field<'_>) -> Result> { let field_attrs = FieldAttr::from_attrs(FieldAttr::NAME, &field.attrs)?; let parent_attrs = FieldAttr::from_attrs(FieldAttr::NAME, field.parent.attrs())?; @@ -446,10 +446,12 @@ pub fn default<'v>(field: Field<'v>) -> Result> { } } +type Dup = (usize, Span, Span); + pub fn first_duplicate( keys: impl Iterator + Clone, values: impl Fn(&K) -> Result>, -) -> Result> { +) -> Result> { let (mut all_values, mut key_map) = (vec![], vec![]); for key in keys { all_values.append(&mut values(&key)?); diff --git a/core/codegen/src/derive/responder.rs b/core/codegen/src/derive/responder.rs index 64df49e8..736ee97d 100644 --- a/core/codegen/src/derive/responder.rs +++ b/core/codegen/src/derive/responder.rs @@ -79,7 +79,7 @@ pub fn derive_responder(input: proc_macro::TokenStream) -> TokenStream { let responder = fields.iter().next().map(|f| { let (accessor, ty) = (f.accessor(), f.ty.with_stripped_lifetimes()); - quote_spanned! { f.span().into() => + quote_spanned! { f.span() => let mut __res = <#ty as #_response::Responder>::respond_to( #accessor, __req )?; diff --git a/core/codegen/src/exports.rs b/core/codegen/src/exports.rs index 1c947ac3..7ceff13a 100644 --- a/core/codegen/src/exports.rs +++ b/core/codegen/src/exports.rs @@ -99,7 +99,6 @@ define_exported_paths! { StaticCatcherInfo => ::rocket::StaticCatcherInfo, Route => ::rocket::Route, Catcher => ::rocket::Catcher, - SmallVec => ::rocket::http::private::SmallVec, Status => ::rocket::http::Status, } diff --git a/core/codegen/tests/route-format.rs b/core/codegen/tests/route-format.rs index c0d927d7..be05eab3 100644 --- a/core/codegen/tests/route-format.rs +++ b/core/codegen/tests/route-format.rs @@ -89,10 +89,10 @@ fn test_custom_formats() { let client = Client::debug(rocket).unwrap(); - let foo_a = Accept::new([MediaType::new("application", "foo").into()]); + let foo_a = Accept::new([MediaType::new("application", "foo")]); let foo_ct = ContentType::new("application", "foo"); let bar_baz_ct = ContentType::new("bar", "baz"); - let bar_baz_a = Accept::new([MediaType::new("bar", "baz").into()]); + let bar_baz_a = Accept::new([MediaType::new("bar", "baz")]); let response = client.get("/").header(foo_a).dispatch(); assert_eq!(response.into_string().unwrap(), "get_foo"); diff --git a/core/http/Cargo.toml b/core/http/Cargo.toml index 5474e9e3..dc94c860 100644 --- a/core/http/Cargo.toml +++ b/core/http/Cargo.toml @@ -20,15 +20,20 @@ default = [] serde = ["uncased/with-serde-alloc", "serde_"] uuid = ["uuid_"] +[lints.clippy] +module_inception = "allow" +multiple_bound_locations = "allow" +manual_range_contains = "allow" + [dependencies] -smallvec = { version = "1.11", features = ["const_generics", "const_new"] } +tinyvec = { version = "1.6", features = ["std", "rustc_1_57"] } percent-encoding = "2" time = { version = "0.3", features = ["formatting", "macros"] } indexmap = "2" ref-cast = "1.0" uncased = "0.9.10" either = "1" -pear = "0.2.8" +pear = "0.2.9" memchr = "2" stable-pattern = "0.1" cookie = { version = "0.18", features = ["percent-encode"] } diff --git a/core/http/src/ext.rs b/core/http/src/ext.rs index 65629c58..557cbaba 100644 --- a/core/http/src/ext.rs +++ b/core/http/src/ext.rs @@ -1,75 +1,9 @@ //! Extension traits implemented by several HTTP types. -use smallvec::{Array, SmallVec}; -use state::InitCell; - -// TODO: It would be nice if we could somehow have one trait that could give us -// either SmallVec or Vec. -/// Trait implemented by types that can be converted into a collection. -pub trait IntoCollection: Sized { - /// Converts `self` into a collection. - fn into_collection>(self) -> SmallVec; - - #[doc(hidden)] - fn mapped U, A: Array>(self, f: F) -> SmallVec; -} - -impl IntoCollection for T { - #[inline] - fn into_collection>(self) -> SmallVec { - let mut vec = SmallVec::new(); - vec.push(self); - vec - } - - #[inline(always)] - fn mapped U, A: Array>(self, mut f: F) -> SmallVec { - f(self).into_collection() - } -} - -impl IntoCollection for Vec { - #[inline(always)] - fn into_collection>(self) -> SmallVec { - SmallVec::from_vec(self) - } - - #[inline] - fn mapped U, A: Array>(self, f: F) -> SmallVec { - self.into_iter().map(f).collect() - } -} - -impl IntoCollection for &[T] { - #[inline(always)] - fn into_collection>(self) -> SmallVec { - self.iter().cloned().collect() - } - - #[inline] - fn mapped>(self, f: F) -> SmallVec - where F: FnMut(T) -> U - { - self.iter().cloned().map(f).collect() - } -} - -impl IntoCollection for [T; N] { - #[inline(always)] - fn into_collection>(self) -> SmallVec { - self.into_iter().collect() - } - - #[inline] - fn mapped>(self, f: F) -> SmallVec - where F: FnMut(T) -> U - { - self.into_iter().map(f).collect() - } -} - use std::borrow::Cow; +use state::InitCell; + /// Trait implemented by types that can be converted into owned versions of /// themselves. pub trait IntoOwned { diff --git a/core/http/src/header/accept.rs b/core/http/src/header/accept.rs index c38e4932..d3527597 100644 --- a/core/http/src/header/accept.rs +++ b/core/http/src/header/accept.rs @@ -1,11 +1,9 @@ +use std::borrow::Cow; use std::ops::Deref; use std::str::FromStr; use std::fmt; -use smallvec::SmallVec; - use crate::{Header, MediaType}; -use crate::ext::IntoCollection; use crate::parse::parse_accept; /// The HTTP Accept header. @@ -52,7 +50,7 @@ use crate::parse::parse_accept; /// let response = Response::build().header(Accept::JSON).finalize(); /// ``` #[derive(Debug, Clone)] -pub struct Accept(pub(crate) SmallVec<[QMediaType; 1]>); +pub struct Accept(pub(crate) Cow<'static, [QMediaType]>); /// A `MediaType` with an associated quality value. #[derive(Debug, Clone, PartialEq)] @@ -65,9 +63,10 @@ macro_rules! accept_constructor { #[doc="An `Accept` header with the single media type for"] #[doc=concat!("**", $str, "**: ", "_", $t, "/", $s, "_")] #[allow(non_upper_case_globals)] - pub const $name: Accept = Accept( - SmallVec::from_const([QMediaType(MediaType::$name, None)]) - ); + pub const $name: Accept = Accept({ + const INNER: &[QMediaType] = &[QMediaType(MediaType::$name, None)]; + Cow::Borrowed(INNER) + }); )+ }; } @@ -86,29 +85,48 @@ impl Accept { /// # extern crate rocket; /// use rocket::http::{QMediaType, MediaType, Accept}; /// - /// // Construct an `Accept` via a `Vec`. - /// let json_then_html = vec![MediaType::JSON.into(), MediaType::HTML.into()]; + /// // Construct an `Accept` via a `Vec`. + /// let json_then_html = vec![MediaType::JSON, MediaType::HTML]; /// let accept = Accept::new(json_then_html); /// assert_eq!(accept.preferred().media_type(), &MediaType::JSON); /// - /// // Construct an `Accept` via an `[QMediaType]`. - /// let accept = Accept::new([MediaType::JSON.into(), MediaType::HTML.into()]); + /// // Construct an `Accept` via an `[MediaType]`. + /// let accept = Accept::new([MediaType::JSON, MediaType::HTML]); /// assert_eq!(accept.preferred().media_type(), &MediaType::JSON); /// - /// // Construct an `Accept` via a `QMediaType`. - /// let accept = Accept::new(QMediaType(MediaType::JSON, None)); + /// // Construct an `Accept` via a single `QMediaType`. + /// let accept = Accept::new(QMediaType(MediaType::JSON, Some(0.4))); /// assert_eq!(accept.preferred().media_type(), &MediaType::JSON); /// ``` #[inline(always)] - pub fn new>(items: T) -> Accept { - Accept(items.into_collection()) + pub fn new, M: Into>(items: T) -> Accept { + Accept(items.into_iter().map(|v| v.into()).collect()) } - // TODO: Implement this. - // #[inline(always)] - // pub fn add>(&mut self, media_type: M) { - // self.0.push(media_type.into()); - // } + /// Adds `media_type` to `self`. + /// + /// # Example + /// + /// ```rust + /// # extern crate rocket; + /// use rocket::http::{QMediaType, MediaType, Accept}; + /// + /// let mut accept = Accept::new(QMediaType(MediaType::JSON, Some(0.1))); + /// assert_eq!(accept.preferred().media_type(), &MediaType::JSON); + /// assert_eq!(accept.iter().count(), 1); + /// + /// accept.add(QMediaType(MediaType::HTML, Some(0.7))); + /// assert_eq!(accept.preferred().media_type(), &MediaType::HTML); + /// assert_eq!(accept.iter().count(), 2); + /// + /// accept.add(QMediaType(MediaType::XML, Some(0.6))); + /// assert_eq!(accept.preferred().media_type(), &MediaType::HTML); + /// assert_eq!(accept.iter().count(), 3); + /// ``` + #[inline(always)] + pub fn add>(&mut self, media_type: M) { + self.0.to_mut().push(media_type.into()); + } /// Retrieve the client's preferred media type. This method follows [RFC /// 7231 5.3.2]. If the list of media types is empty, this method returns a @@ -233,10 +251,10 @@ impl Accept { known_media_types!(accept_constructor); } -impl> From for Accept { +impl> From for Accept { #[inline(always)] fn from(items: T) -> Accept { - Accept(items.mapped(|item| item.into())) + Accept::new(items.into_iter().map(QMediaType::from)) } } @@ -332,6 +350,16 @@ impl QMediaType { } } +impl IntoIterator for QMediaType { + type Item = Self; + + type IntoIter = std::iter::Once; + + fn into_iter(self) -> Self::IntoIter { + std::iter::once(self) + } +} + impl From for QMediaType { #[inline(always)] fn from(media_type: MediaType) -> QMediaType { diff --git a/core/http/src/header/content_type.rs b/core/http/src/header/content_type.rs index f7394ab5..8a26327f 100644 --- a/core/http/src/header/content_type.rs +++ b/core/http/src/header/content_type.rs @@ -5,7 +5,6 @@ use std::fmt; use crate::header::{Header, MediaType}; use crate::uncased::UncasedStr; -use crate::ext::IntoCollection; /// Representation of HTTP Content-Types. /// @@ -247,7 +246,7 @@ impl ContentType { /// # extern crate rocket; /// use rocket::http::ContentType; /// - /// let id = ContentType::new("application", "x-id").with_params(("id", "1")); + /// let id = ContentType::new("application", "x-id").with_params([("id", "1")]); /// assert_eq!(id.to_string(), "application/x-id; id=1".to_string()); /// ``` /// @@ -265,7 +264,7 @@ impl ContentType { pub fn with_params(self, parameters: P) -> ContentType where K: Into>, V: Into>, - P: IntoCollection<(K, V)> + P: IntoIterator { ContentType(self.0.with_params(parameters)) } diff --git a/core/http/src/header/header.rs b/core/http/src/header/header.rs index 8a76b6a3..11fa6f94 100644 --- a/core/http/src/header/header.rs +++ b/core/http/src/header/header.rs @@ -90,11 +90,9 @@ impl<'h> Header<'h> { #[doc(hidden)] pub const fn is_valid_name(name: &str) -> bool { const fn is_tchar(b: &u8) -> bool { - b.is_ascii_alphanumeric() || match *b { + b.is_ascii_alphanumeric() || matches!(*b, b'!' | b'#' | b'$' | b'%' | b'&' | b'\'' | b'*' | b'+' | b'-' | - b'.' | b'^' | b'_' | b'`' | b'|' | b'~' => true, - _ => false - } + b'.' | b'^' | b'_' | b'`' | b'|' | b'~') } let mut i = 0; @@ -522,7 +520,7 @@ impl<'h> HeaderMap<'h> { #[inline(always)] pub fn add<'p: 'h, H: Into>>(&mut self, header: H) { let header = header.into(); - self.headers.entry(header.name).or_insert(vec![]).push(header.value); + self.headers.entry(header.name).or_default().push(header.value); } /// A convenience method to add a header using a raw name and value. @@ -580,7 +578,7 @@ impl<'h> HeaderMap<'h> { where 'n:'h, H: Into> { self.headers.entry(Uncased::new(name)) - .or_insert(vec![]) + .or_default() .append(values) } @@ -660,6 +658,7 @@ impl<'h> HeaderMap<'h> { /// /// // The headers we'll be storing. /// let all_headers = vec![ + /// Header::new("X-Custom", "value_0"), /// Header::new("X-Custom", "value_1"), /// Header::new("X-Other", "other"), /// Header::new("X-Third", "third"), @@ -672,15 +671,19 @@ impl<'h> HeaderMap<'h> { /// } /// /// // Ensure there are three headers via the iterator. - /// assert_eq!(map.iter().count(), 3); + /// assert_eq!(map.iter().count(), 4); /// /// // Actually iterate through them. + /// let mut custom = 0; /// for header in map.iter() { /// match header.name().as_str() { - /// "X-Custom" => assert_eq!(header.value(), "value_1"), /// "X-Other" => assert_eq!(header.value(), "other"), /// "X-Third" => assert_eq!(header.value(), "third"), - /// _ => unreachable!("there are only three headers") + /// "X-Custom" => { + /// assert_eq!(header.value(), format!("value_{custom}")); + /// custom += 1; + /// }, + /// _ => unreachable!("there are only three uniquely named headers") /// } /// } /// ``` @@ -692,53 +695,6 @@ impl<'h> HeaderMap<'h> { }) } - /// Consumes `self` and returns an iterator over all of the `Header`s stored - /// in the map. Header names are returned in no specific order, but all - /// values for a given header name are grouped together, and values are in - /// FIFO order. - /// - /// # Example - /// - /// ```rust - /// # extern crate rocket; - /// use rocket::http::{HeaderMap, Header}; - /// - /// // The headers we'll be storing. - /// let all_headers = vec![ - /// Header::new("X-Custom", "value_1"), - /// Header::new("X-Other", "other"), - /// Header::new("X-Third", "third"), - /// ]; - /// - /// // Create a map, store all of the headers. - /// let mut map = HeaderMap::new(); - /// for header in all_headers { - /// map.add(header) - /// } - /// - /// // Ensure there are three headers via the iterator. - /// assert_eq!(map.iter().count(), 3); - /// - /// // Actually iterate through them. - /// for header in map.into_iter() { - /// match header.name().as_str() { - /// "X-Custom" => assert_eq!(header.value(), "value_1"), - /// "X-Other" => assert_eq!(header.value(), "other"), - /// "X-Third" => assert_eq!(header.value(), "third"), - /// _ => unreachable!("there are only three headers") - /// } - /// } - /// ``` - // TODO: Implement IntoIterator. - #[inline(always)] - pub fn into_iter(self) -> impl Iterator> { - self.headers.into_iter().flat_map(|(name, value)| { - value.into_iter().map(move |value| { - Header { name: name.clone(), value } - }) - }) - } - /// Consumes `self` and returns an iterator over all of the headers stored /// in the map in the way they are stored. This is a low-level mechanism and /// should likely not be used. @@ -750,6 +706,86 @@ impl<'h> HeaderMap<'h> { } } +/// Consumes `self` and returns an iterator over all of the `Header`s stored +/// in the map. Header names are returned in no specific order, but all +/// values for a given header name are grouped together, and values are in +/// FIFO order. +/// +/// # Example +/// +/// ```rust +/// # extern crate rocket; +/// use rocket::http::{HeaderMap, Header}; +/// +/// // The headers we'll be storing. +/// let all_headers = vec![ +/// Header::new("X-Custom", "value_0"), +/// Header::new("X-Custom", "value_1"), +/// Header::new("X-Other", "other"), +/// Header::new("X-Third", "third"), +/// ]; +/// +/// // Create a map, store all of the headers. +/// let mut map = HeaderMap::new(); +/// for header in all_headers { +/// map.add(header) +/// } +/// +/// // Ensure there are three headers via the iterator. +/// assert_eq!(map.iter().count(), 4); +/// +/// // Actually iterate through them. +/// let mut custom = 0; +/// for header in map.into_iter() { +/// match header.name().as_str() { +/// "X-Other" => assert_eq!(header.value(), "other"), +/// "X-Third" => assert_eq!(header.value(), "third"), +/// "X-Custom" => { +/// assert_eq!(header.value(), format!("value_{custom}")); +/// custom += 1; +/// }, +/// _ => unreachable!("there are only three uniquely named headers") +/// } +/// } +/// ``` +impl<'h> IntoIterator for HeaderMap<'h> { + type Item = Header<'h>; + + type IntoIter = IntoIter<'h>; + + fn into_iter(self) -> Self::IntoIter { + IntoIter { + headers: self.headers.into_iter(), + current: None, + } + } +} + +/// Owned iterator over [`Header`]s in a [`HeaderMap`]. +/// +/// See [`HeaderMap::into_iter()`] for details. +pub struct IntoIter<'h> { + headers: indexmap::map::IntoIter, Vec>>, + current: Option<(Uncased<'h>, std::vec::IntoIter>)>, +} + +impl<'h> Iterator for IntoIter<'h> { + type Item = Header<'h>; + + fn next(&mut self) -> Option { + loop { + if let Some((name, values)) = &mut self.current { + if let Some(value) = values.next() { + return Some(Header { name: name.clone(), value }); + } + } + + let (name, values) = self.headers.next()?; + self.current = Some((name, values.into_iter())); + } + } +} + impl From> for Header<'static> { fn from(cookie: cookie::Cookie<'_>) -> Header<'static> { Header::new("Set-Cookie", cookie.encoded().to_string()) diff --git a/core/http/src/header/media_type.rs b/core/http/src/header/media_type.rs index 0d637a81..691ac24d 100644 --- a/core/http/src/header/media_type.rs +++ b/core/http/src/header/media_type.rs @@ -5,12 +5,9 @@ use std::hash::{Hash, Hasher}; use either::Either; -use crate::ext::IntoCollection; use crate::uncased::UncasedStr; use crate::parse::{Indexed, IndexedStr, parse_media_type}; -use smallvec::SmallVec; - /// An HTTP media type. /// /// # Usage @@ -58,14 +55,14 @@ pub struct MediaType { /// The subtype. pub(crate) sub: IndexedStr<'static>, /// The parameters, if any. - pub(crate) params: MediaParams + pub(crate) params: MediaParams, } -// FIXME: `Static` variant is needed for `const`. Need `const SmallVec::new`. +// TODO: `Static` variant is needed for `const`. #[derive(Debug, Clone)] pub(crate) enum MediaParams { Static(&'static [(&'static str, &'static str)]), - Dynamic(SmallVec<[(IndexedStr<'static>, IndexedStr<'static>); 2]>) + Dynamic(Vec<(IndexedStr<'static>, IndexedStr<'static>)>) } #[derive(Debug, Clone, PartialEq, Eq)] @@ -309,7 +306,7 @@ impl MediaType { /// # extern crate rocket; /// use rocket::http::MediaType; /// - /// let id = MediaType::new("application", "x-id").with_params(("id", "1")); + /// let id = MediaType::new("application", "x-id").with_params([("id", "1")]); /// assert_eq!(id.to_string(), "application/x-id; id=1".to_string()); /// ``` /// @@ -327,11 +324,12 @@ impl MediaType { pub fn with_params(mut self, ps: P) -> MediaType where K: Into>, V: Into>, - P: IntoCollection<(K, V)> + P: IntoIterator { - use Indexed::Concrete; + let params = ps.into_iter() + .map(|(k, v)| (Indexed::Concrete(k.into()), Indexed::Concrete(v.into()))) + .collect(); - let params = ps.mapped(|(k, v)| (Concrete(k.into()), Concrete(v.into()))); self.params = MediaParams::Dynamic(params); self } @@ -478,7 +476,7 @@ impl MediaType { /// use rocket::http::MediaType; /// /// let plain = MediaType::Plain; - /// let plain2 = MediaType::new("text", "plain").with_params(("charset", "utf-8")); + /// let plain2 = MediaType::new("text", "plain").with_params([("charset", "utf-8")]); /// let just_plain = MediaType::new("text", "plain"); /// /// // The `PartialEq` implementation doesn't consider parameters. @@ -527,7 +525,7 @@ impl MediaType { let raw = match self.params { MediaParams::Static(slice) => Either::Left(slice.iter().cloned()), MediaParams::Dynamic(ref vec) => { - Either::Right(vec.iter().map(move |&(ref key, ref val)| { + Either::Right(vec.iter().map(move |(key, val)| { let source_str = self.source.as_str(); (key.from_source(source_str), val.from_source(source_str)) })) @@ -594,9 +592,19 @@ impl fmt::Display for MediaType { } } +impl IntoIterator for MediaType { + type Item = Self; + + type IntoIter = std::iter::Once; + + fn into_iter(self) -> Self::IntoIter { + std::iter::once(self) + } +} + impl Default for MediaParams { fn default() -> Self { - MediaParams::Dynamic(SmallVec::new()) + MediaParams::Dynamic(Vec::new()) } } diff --git a/core/http/src/lib.rs b/core/http/src/lib.rs index 86935cce..86950c24 100644 --- a/core/http/src/lib.rs +++ b/core/http/src/lib.rs @@ -33,7 +33,6 @@ pub mod uncased { #[path = "."] pub mod private { pub use crate::parse::Indexed; - pub use smallvec::{SmallVec, Array}; } pub use crate::method::Method; diff --git a/core/http/src/method.rs b/core/http/src/method.rs index 11e031d4..e47461ac 100644 --- a/core/http/src/method.rs +++ b/core/http/src/method.rs @@ -140,7 +140,7 @@ mod serde { use serde_::ser::{Serialize, Serializer}; use serde_::de::{Deserialize, Deserializer, Error, Visitor, Unexpected}; - impl<'a> Serialize for Method { + impl Serialize for Method { fn serialize(&self, serializer: S) -> Result { serializer.serialize_str(self.as_str()) } diff --git a/core/http/src/parse/accept.rs b/core/http/src/parse/accept.rs index 6ea87e13..42d00a9c 100644 --- a/core/http/src/parse/accept.rs +++ b/core/http/src/parse/accept.rs @@ -31,7 +31,8 @@ fn weighted_media_type<'a>(input: &mut Input<'a>) -> Result<'a, QMediaType> { #[parser] fn accept<'a>(input: &mut Input<'a>) -> Result<'a, Accept> { - Accept(series(|i| surrounded(i, weighted_media_type, is_whitespace), ',')?) + let vec = series(|i| surrounded(i, weighted_media_type, is_whitespace), ',')?; + Accept(std::borrow::Cow::Owned(vec)) } pub fn parse_accept(input: &str) -> Result<'_, Accept> { diff --git a/core/http/src/parse/indexed.rs b/core/http/src/parse/indexed.rs index d488e036..58ff2d8f 100644 --- a/core/http/src/parse/indexed.rs +++ b/core/http/src/parse/indexed.rs @@ -211,8 +211,8 @@ impl<'a, T: ?Sized + ToOwned + 'a> Indexed<'a, T> } match *self { - Indexed::Indexed(i, j) => &source.unwrap()[(i as usize)..(j as usize)], - Indexed::Concrete(ref mstr) => &*mstr, + Indexed::Indexed(i, j) => &source.unwrap()[i..j], + Indexed::Concrete(ref mstr) => mstr, } } } @@ -241,7 +241,7 @@ impl<'a, T: ?Sized + Length + ToOwned + 'a> Length for Indexed<'a, T> { #[inline(always)] fn len(&self) -> usize { match *self { - Indexed::Indexed(a, b) => (b - a) as usize, + Indexed::Indexed(a, b) => b.saturating_sub(a), Indexed::Concrete(ref cow) => cow.len() } } diff --git a/core/http/src/parse/uri/tests.rs b/core/http/src/parse/uri/tests.rs index 1f37c604..89bb6b88 100644 --- a/core/http/src/parse/uri/tests.rs +++ b/core/http/src/parse/uri/tests.rs @@ -79,7 +79,7 @@ fn test_assert_parse_eq() { #[should_panic] fn test_assert_parse_eq_consecutive() { assert_parse_eq! { - "/" => Origin::ROOT, + "/" => Origin::root(), "/" => Asterisk }; } @@ -130,7 +130,7 @@ fn test_parse_issue_924_samples() { fn single_byte() { assert_parse_eq!( "*" => Asterisk, - "/" => Origin::ROOT, + "/" => Origin::root(), "." => Authority::new(None, ".", None), "_" => Authority::new(None, "_", None), "1" => Authority::new(None, "1", None), diff --git a/core/http/src/status.rs b/core/http/src/status.rs index 5de8e50e..8cc929dd 100644 --- a/core/http/src/status.rs +++ b/core/http/src/status.rs @@ -370,7 +370,7 @@ impl Eq for Status { } impl PartialOrd for Status { fn partial_cmp(&self, other: &Self) -> Option { - self.code.partial_cmp(&other.code) + Some(self.cmp(other)) } } @@ -387,7 +387,7 @@ mod serde { use serde_::ser::{Serialize, Serializer}; use serde_::de::{Deserialize, Deserializer, Error, Visitor, Unexpected}; - impl<'a> Serialize for Status { + impl Serialize for Status { fn serialize(&self, serializer: S) -> Result { serializer.serialize_u16(self.code) } diff --git a/core/http/src/uri/absolute.rs b/core/http/src/uri/absolute.rs index 385f754a..03517ced 100644 --- a/core/http/src/uri/absolute.rs +++ b/core/http/src/uri/absolute.rs @@ -309,10 +309,8 @@ impl<'a> Absolute<'a> { if !self.path().is_normalized(true) { self.path = self.path().to_normalized(true, true); } - } else { - if !self.path().is_normalized(false) { - self.path = self.path().to_normalized(false, true); - } + } else if !self.path().is_normalized(false) { + self.path = self.path().to_normalized(false, true); } if let Some(query) = self.query() { diff --git a/core/http/src/uri/fmt/formatter.rs b/core/http/src/uri/fmt/formatter.rs index 9f79a470..eca86b72 100644 --- a/core/http/src/uri/fmt/formatter.rs +++ b/core/http/src/uri/fmt/formatter.rs @@ -2,8 +2,6 @@ use std::fmt::{self, Write}; use std::marker::PhantomData; use std::borrow::Cow; -use smallvec::SmallVec; - use crate::uri::{Absolute, Origin, Reference}; use crate::uri::fmt::{UriDisplay, Part, Path, Query, Kind}; @@ -143,7 +141,7 @@ use crate::uri::fmt::{UriDisplay, Part, Path, Query, Kind}; /// [`write_raw()`]: Formatter::write_raw() /// [`refresh()`]: Formatter::refresh() pub struct Formatter<'i, P: Part> { - prefixes: SmallVec<[&'static str; 3]>, + prefixes: tinyvec::TinyVec<[&'static str; 3]>, inner: &'i mut (dyn Write + 'i), previous: bool, fresh: bool, @@ -155,7 +153,7 @@ impl<'i, P: Part> Formatter<'i, P> { pub(crate) fn new(inner: &'i mut (dyn Write + 'i)) -> Self { Formatter { inner, - prefixes: SmallVec::new(), + prefixes: Default::default(), previous: false, fresh: true, _marker: PhantomData, @@ -357,7 +355,7 @@ impl Formatter<'_, Query> { } } - f(&mut PrefixGuard::new(prefix, self).0) + f(PrefixGuard::new(prefix, self).0) } /// Writes the named value `value` by prefixing `name` followed by `=` to diff --git a/core/http/src/uri/origin.rs b/core/http/src/uri/origin.rs index 42aa917d..96d8eeb4 100644 --- a/core/http/src/uri/origin.rs +++ b/core/http/src/uri/origin.rs @@ -121,7 +121,10 @@ pub struct Origin<'a> { impl<'a> Origin<'a> { /// The root: `'/'`. #[doc(hidden)] - pub const ROOT: Origin<'static> = Origin::const_new("/", None); + pub fn root() -> &'static Origin<'static> { + static ROOT_ORIGIN: Origin<'static> = Origin::const_new("/", None); + &ROOT_ORIGIN + } /// SAFETY: `source` must be UTF-8. #[inline] @@ -218,7 +221,7 @@ impl<'a> Origin<'a> { if !string.starts_with('/') { return Err(Error { - expected: Expected::token(Some(&b'/'), string.as_bytes().get(0).cloned()), + expected: Expected::token(Some(&b'/'), string.as_bytes().first().cloned()), index: 0, }); } diff --git a/core/http/src/uri/reference.rs b/core/http/src/uri/reference.rs index a6269506..5c79e7ad 100644 --- a/core/http/src/uri/reference.rs +++ b/core/http/src/uri/reference.rs @@ -366,10 +366,8 @@ impl<'a> Reference<'a> { if !self.path().is_normalized(true) { self.path = self.path().to_normalized(true, true); } - } else { - if !self.path().is_normalized(false) { - self.path = self.path().to_normalized(false, true); - } + } else if !self.path().is_normalized(false) { + self.path = self.path().to_normalized(false, true); } if let Some(query) = self.query() { diff --git a/core/http/src/uri/segments.rs b/core/http/src/uri/segments.rs index 9d62edc5..6760c1dc 100644 --- a/core/http/src/uri/segments.rs +++ b/core/http/src/uri/segments.rs @@ -235,7 +235,7 @@ impl<'a> Segments<'a, Path> { } else if cfg!(windows) && segment.contains(':') { return Err(PathError::BadChar(':')) } else { - buf.push(&*segment) + buf.push(segment) } } diff --git a/core/http/src/uri/uri.rs b/core/http/src/uri/uri.rs index 14247670..e997773a 100644 --- a/core/http/src/uri/uri.rs +++ b/core/http/src/uri/uri.rs @@ -334,6 +334,24 @@ macro_rules! impl_uri_from { } } } + + impl<'b, $($lt)?> PartialEq<&$T $(<$lt>)?> for Uri<'b> { + fn eq(&self, other: &&$T $(<$lt>)?) -> bool { + match self { + Uri::$T(inner) => inner == *other, + _ => false + } + } + } + + impl<'b, $($lt)?> PartialEq> for &$T $(<$lt>)? { + fn eq(&self, other: &Uri<'b>) -> bool { + match other { + Uri::$T(inner) => inner == *self, + _ => false + } + } + } ) } diff --git a/core/lib/Cargo.toml b/core/lib/Cargo.toml index 2c433d66..6a423294 100644 --- a/core/lib/Cargo.toml +++ b/core/lib/Cargo.toml @@ -19,6 +19,18 @@ rust-version = "1.75" [package.metadata.docs.rs] all-features = true +[lints.rust] +rust_2018_idioms = "warn" +# missing_docs = "warn" +async_fn_in_trait = "allow" +refining_impl_trait = "allow" + +[lints.clippy] +type_complexity = "allow" +module_inception = "allow" +multiple_bound_locations = "allow" +manual_range_contains = "allow" + [features] default = ["http2", "tokio-macros"] http2 = ["hyper/http2", "hyper-util/http2"] diff --git a/core/lib/src/catcher/catcher.rs b/core/lib/src/catcher/catcher.rs index 299d7b08..de996205 100644 --- a/core/lib/src/catcher/catcher.rs +++ b/core/lib/src/catcher/catcher.rs @@ -134,7 +134,7 @@ pub struct Catcher { // The rank is computed as -(number of nonempty segments in base) => catchers // with more nonempty segments have lower ranks => higher precedence. fn rank(base: Path<'_>) -> isize { - -1 * (base.segments().filter(|s| !s.is_empty()).count() as isize) + -(base.segments().filter(|s| !s.is_empty()).count() as isize) } impl Catcher { @@ -184,9 +184,9 @@ impl Catcher { Catcher { name: None, - base: uri::Origin::ROOT, + base: uri::Origin::root().clone(), handler: Box::new(handler), - rank: rank(uri::Origin::ROOT.path()), + rank: rank(uri::Origin::root().path()), code } } diff --git a/core/lib/src/config/config.rs b/core/lib/src/config/config.rs index ea8c8611..00560b76 100644 --- a/core/lib/src/config/config.rs +++ b/core/lib/src/config/config.rs @@ -315,7 +315,7 @@ impl Config { #[cfg(feature = "secrets")] pub(crate) fn known_secret_key_used(&self) -> bool { - const KNOWN_SECRET_KEYS: &'static [&'static str] = &[ + const KNOWN_SECRET_KEYS: &[&str] = &[ "hPRYyVRiMyxpw5sBB1XeCMN1kFsDCqKvBi2QJxBVHQk=" ]; @@ -363,7 +363,7 @@ impl Config { None => launch_meta_!("Proxy-Proto header: {}", "disabled".paint(VAL)) } - launch_meta_!("limits: {}", (&self.limits).paint(VAL)); + launch_meta_!("limits: {}", self.limits.paint(VAL)); launch_meta_!("temp dir: {}", self.temp_dir.relative().display().paint(VAL)); launch_meta_!("http/2: {}", (cfg!(feature = "http2").paint(VAL))); diff --git a/core/lib/src/config/ident.rs b/core/lib/src/config/ident.rs index 28a7f7b4..6387fcf5 100644 --- a/core/lib/src/config/ident.rs +++ b/core/lib/src/config/ident.rs @@ -80,7 +80,7 @@ pub struct Ident(Option); macro_rules! ident { ($value:expr) => { { - #[allow(unknown_lints, eq_op)] + #[allow(unknown_lints)] const _: [(); 0 - !{ const ASSERT: bool = $crate::http::Header::is_valid_value($value, false); ASSERT diff --git a/core/lib/src/data/peekable.rs b/core/lib/src/data/peekable.rs index 58daac70..62896735 100644 --- a/core/lib/src/data/peekable.rs +++ b/core/lib/src/data/peekable.rs @@ -22,7 +22,7 @@ impl Peekable { let to_read = std::cmp::min(N, num); if self.buffer.len() >= to_read { - return &self.buffer.as_slice(); + return self.buffer.as_slice(); } if self.buffer.capacity() == 0 { diff --git a/core/lib/src/data/transform.rs b/core/lib/src/data/transform.rs index f52478e6..ea5f0895 100644 --- a/core/lib/src/data/transform.rs +++ b/core/lib/src/data/transform.rs @@ -157,13 +157,13 @@ impl<'a, 'b> Deref for TransformBuf<'a, 'b> { type Target = ReadBuf<'b>; fn deref(&self) -> &Self::Target { - &self.buf + self.buf } } impl<'a, 'b> DerefMut for TransformBuf<'a, 'b> { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.buf + self.buf } } diff --git a/core/lib/src/erased.rs b/core/lib/src/erased.rs index 966ff2dd..1c0900a8 100644 --- a/core/lib/src/erased.rs +++ b/core/lib/src/erased.rs @@ -67,11 +67,11 @@ impl ErasedRequest { let rocket: Arc> = rocket; let parts: Box = Box::new(parts); let request: Request<'_> = { - let rocket: &Rocket = &*rocket; + let rocket: &Rocket = &rocket; let rocket: &'static Rocket = unsafe { transmute(rocket) }; - let parts: &Parts = &*parts; + let parts: &Parts = &parts; let parts: &'static Parts = unsafe { transmute(parts) }; - constructor(&rocket, &parts) + constructor(rocket, parts) }; ErasedRequest { _rocket: rocket, _parts: parts, request, } @@ -99,7 +99,7 @@ impl ErasedRequest { let mut parent = Arc::new(self); let token: T = { let parent: &mut ErasedRequest = Arc::get_mut(&mut parent).unwrap(); - let rocket: &Rocket = &*parent._rocket; + let rocket: &Rocket = &parent._rocket; let request: &mut Request<'_> = &mut parent.request; let data: &mut Data<'_> = &mut data; preprocess(rocket, request, data).await @@ -107,22 +107,22 @@ impl ErasedRequest { let parent = parent; let response: Response<'_> = { - let parent: &ErasedRequest = &*parent; + let parent: &ErasedRequest = &parent; let parent: &'static ErasedRequest = unsafe { transmute(parent) }; - let rocket: &Rocket = &*parent._rocket; + let rocket: &Rocket = &parent._rocket; let request: &Request<'_> = &parent.request; dispatch(token, rocket, request, data).await }; ErasedResponse { _request: parent, - response: response, + response, } } } impl ErasedResponse { - pub fn inner<'a>(&'a self) -> &'a Response<'a> { + pub fn inner(&self) -> &Response<'_> { static_assert_covariance!(Response); &self.response } @@ -135,7 +135,7 @@ impl ErasedResponse { f(&mut self.response) } - pub fn to_io_handler<'a>( + pub fn make_io_handler<'a>( &'a mut self, constructor: impl for<'r> FnOnce( &'r Request<'r>, @@ -144,7 +144,7 @@ impl ErasedResponse { ) -> Option { let parent: Arc = self._request.clone(); let io: Option> = { - let parent: &ErasedRequest = &*parent; + let parent: &ErasedRequest = &parent; let parent: &'static ErasedRequest = unsafe { transmute(parent) }; let request: &Request<'_> = &parent.request; constructor(request, &mut self.response) diff --git a/core/lib/src/error.rs b/core/lib/src/error.rs index b072dd77..473eb8a8 100644 --- a/core/lib/src/error.rs +++ b/core/lib/src/error.rs @@ -92,7 +92,7 @@ pub enum ErrorKind { InsecureSecretKey(Profile), /// Liftoff failed. Contains the Rocket instance that failed to shutdown. Liftoff( - Result, Arc>>, + Result>, Arc>>, Box ), /// Shutdown failed. Contains the Rocket instance that failed to shutdown. @@ -196,7 +196,7 @@ impl Error { if collisions.is_empty() { return } error!("Rocket failed to launch due to the following {} collisions:", kind); - for &(ref a, ref b) in collisions { + for (a, b) in collisions { info_!("{} {} {}", a, "collides with".red().italic(), b) } } @@ -336,7 +336,7 @@ pub(crate) fn log_server_error(error: &(dyn StdError + 'static)) { } } - let mut error: &(dyn StdError + 'static) = &*error; + let mut error: &(dyn StdError + 'static) = error; if error.downcast_ref::().is_some() { warn!("{}", ServerError(error)); while let Some(source) = error.source() { diff --git a/core/lib/src/form/buffer.rs b/core/lib/src/form/buffer.rs index 71efe634..598644bf 100644 --- a/core/lib/src/form/buffer.rs +++ b/core/lib/src/form/buffer.rs @@ -10,18 +10,21 @@ mod private { /// [`local_cache`](crate::request::local_cache) must implement this trait. /// Since this trait is sealed, the types implementing this trait are known /// and finite: `String` and `Vec for all T: Sync + Send + 'static`. - // UNSAFE: Needs to have a stable address when deref'd. + /// + /// # Safety + /// + /// Types implementing this trait must have a stable address when deref'd. pub unsafe trait Shareable: std::ops::Deref + Sync + Send + 'static { - /// The current length of the owned shareable. - fn len(&self) -> usize; + /// The current size of the owned shareable. + fn size(&self) -> usize; } unsafe impl Shareable for String { - fn len(&self) -> usize { self.len() } + fn size(&self) -> usize { self.len() } } unsafe impl Shareable for Vec { - fn len(&self) -> usize { self.len() } + fn size(&self) -> usize { self.len() } } } @@ -36,8 +39,8 @@ pub struct SharedStack { } impl SharedStack - where T::Target: Index, Output = T::Target> + - Index, Output = T::Target> + where T::Target: Index, Output = T::Target> + + Index, Output = T::Target> { /// Creates a new stack. pub fn new() -> Self { @@ -101,11 +104,11 @@ impl SharedStack /// Pushes the strings `a` and `b` onto the stack without allocating for /// both strings. Returns references to the two strings on the stack. - pub(crate) fn push_two<'a, V>(&'a self, a: V, b: V) -> (&'a T::Target, &'a T::Target) + pub(crate) fn push_two(&self, a: V, b: V) -> (&T::Target, &T::Target) where T: From + Extend, { let mut value = T::from(a); - let split_len = value.len(); + let split_len = value.size(); value.extend(Some(b)); self.push_split(value, split_len) } diff --git a/core/lib/src/form/context.rs b/core/lib/src/form/context.rs index 33f42c30..b733c836 100644 --- a/core/lib/src/form/context.rs +++ b/core/lib/src/form/context.rs @@ -130,7 +130,7 @@ impl<'v> Context<'v> { /// } /// ``` pub fn field_value>(&self, name: N) -> Option<&'v str> { - self.values.get(name.as_ref())?.get(0).cloned() + self.values.get(name.as_ref())?.first().cloned() } /// Returns the values, if any, submitted for the _value_ field named @@ -179,8 +179,7 @@ impl<'v> Context<'v> { /// ``` pub fn errors(&self) -> impl Iterator> { self.errors.values() - .map(|e| e.iter()) - .flatten() + .flat_map(|e| e.iter()) .chain(self.form_errors.iter()) } @@ -224,8 +223,7 @@ impl<'v> Context<'v> { where N: AsRef + 'a { self.errors.values() - .map(|e| e.iter()) - .flatten() + .flat_map(|e| e.iter()) .filter(move |e| e.is_for(&name)) } @@ -273,8 +271,7 @@ impl<'v> Context<'v> { where N: AsRef + 'a { self.errors.values() - .map(|e| e.iter()) - .flatten() + .flat_map(|e| e.iter()) .filter(move |e| e.is_for_exactly(&name)) } diff --git a/core/lib/src/form/error.rs b/core/lib/src/form/error.rs index b6f3c506..d6a42a55 100644 --- a/core/lib/src/form/error.rs +++ b/core/lib/src/form/error.rs @@ -727,7 +727,7 @@ impl<'v> Error<'v> { | Multipart(FieldSizeExceeded { .. }) | Multipart(StreamSizeExceeded { .. }) => Status::PayloadTooLarge, Unknown => Status::InternalServerError, - Io(_) | _ if self.entity == Entity::Form => Status::BadRequest, + Io(_) if self.entity == Entity::Form => Status::BadRequest, Custom(status, _) => status, _ => Status::UnprocessableEntity } diff --git a/core/lib/src/form/from_form.rs b/core/lib/src/form/from_form.rs index 4733469a..7bf79148 100644 --- a/core/lib/src/form/from_form.rs +++ b/core/lib/src/form/from_form.rs @@ -810,8 +810,8 @@ impl<'v, K, V> FromForm<'v> for BTreeMap impl<'v, T: FromForm<'v>> FromForm<'v> for Option { type Context = >::Context; - fn init(opts: Options) -> Self::Context { - T::init(Options { strict: true, ..opts }) + fn init(_: Options) -> Self::Context { + T::init(Options { strict: true }) } fn push_value(ctxt: &mut Self::Context, field: ValueField<'v>) { diff --git a/core/lib/src/form/lenient.rs b/core/lib/src/form/lenient.rs index 0f6f6b6c..a07baaf4 100644 --- a/core/lib/src/form/lenient.rs +++ b/core/lib/src/form/lenient.rs @@ -78,8 +78,8 @@ impl<'v, T: FromForm<'v>> FromForm<'v> for Lenient { type Context = T::Context; #[inline(always)] - fn init(opts: Options) -> Self::Context { - T::init(Options { strict: false, ..opts }) + fn init(_: Options) -> Self::Context { + T::init(Options { strict: false }) } #[inline(always)] diff --git a/core/lib/src/form/name/key.rs b/core/lib/src/form/name/key.rs index ed7c0f15..2890190f 100644 --- a/core/lib/src/form/name/key.rs +++ b/core/lib/src/form/name/key.rs @@ -71,7 +71,7 @@ impl Key { /// assert_eq!(key.as_str(), "a:b:c"); /// ``` pub fn as_str(&self) -> &str { - &*self + self } } diff --git a/core/lib/src/form/name/view.rs b/core/lib/src/form/name/view.rs index d7858022..2a5cb729 100644 --- a/core/lib/src/form/name/view.rs +++ b/core/lib/src/form/name/view.rs @@ -158,7 +158,7 @@ impl<'v> NameView<'v> { let string = &self.name[self.end..]; let bytes = string.as_bytes(); - let shift = match bytes.get(0) { + let shift = match bytes.first() { None | Some(b'=') => 0, Some(b'[') => match memchr::memchr(b']', bytes) { Some(j) => j + 1, @@ -243,7 +243,7 @@ impl<'v> NameView<'v> { /// ``` pub fn key_lossy(&self) -> &'v Key { let view = &self.name[self.start..self.end]; - let key = match view.as_bytes().get(0) { + let key = match view.as_bytes().first() { Some(b'.') => &view[1..], Some(b'[') if view.ends_with(']') => &view[1..view.len() - 1], Some(b'[') if self.is_at_last() => &view[1..], diff --git a/core/lib/src/form/strict.rs b/core/lib/src/form/strict.rs index ddd80c8d..1c5b55ac 100644 --- a/core/lib/src/form/strict.rs +++ b/core/lib/src/form/strict.rs @@ -93,8 +93,8 @@ impl<'v, T: FromForm<'v>> FromForm<'v> for Strict { type Context = T::Context; #[inline(always)] - fn init(opts: Options) -> Self::Context { - T::init(Options { strict: true, ..opts }) + fn init(_: Options) -> Self::Context { + T::init(Options { strict: true }) } #[inline(always)] diff --git a/core/lib/src/fs/temp_file.rs b/core/lib/src/fs/temp_file.rs index 95ca53a1..5a61298b 100644 --- a/core/lib/src/fs/temp_file.rs +++ b/core/lib/src/fs/temp_file.rs @@ -356,6 +356,27 @@ impl<'v> TempFile<'v> { } } + /// Returns whether the file is empty. + /// + /// This is equivalent to `file.len() == 0`. + /// + /// This method does not perform any system calls. + /// + /// ```rust + /// # #[macro_use] extern crate rocket; + /// use rocket::fs::TempFile; + /// + /// #[post("/", data = "")] + /// fn handler(file: TempFile<'_>) { + /// if file.is_empty() { + /// assert_eq!(file.len(), 0); + /// } + /// } + /// ``` + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + /// Returns the size, in bytes, of the file. /// /// This method does not perform any system calls. @@ -490,7 +511,7 @@ impl<'v> TempFile<'v> { ) -> io::Result>> { let limit = content_type.as_ref() .and_then(|ct| ct.extension()) - .and_then(|ext| req.limits().find(&["file", ext.as_str()])) + .and_then(|ext| req.limits().find(["file", ext.as_str()])) .or_else(|| req.limits().get("file")) .unwrap_or(Limits::FILE); diff --git a/core/lib/src/http/cookies.rs b/core/lib/src/http/cookies.rs index 5225b05b..56f69477 100644 --- a/core/lib/src/http/cookies.rs +++ b/core/lib/src/http/cookies.rs @@ -252,11 +252,11 @@ impl<'a> CookieJar<'a> { /// ``` pub fn get_pending(&self, name: &str) -> Option> { let ops = self.ops.lock(); - for op in ops.iter().rev().filter(|op| op.cookie().name() == name) { - match op { - Op::Add(c, _) => return Some(c.clone()), - Op::Remove(_) => return None, - } + if let Some(op) = ops.iter().rev().find(|op| op.cookie().name() == name) { + return match op { + Op::Add(c, _) => Some(c.clone()), + Op::Remove(_) => None, + }; } drop(ops); diff --git a/core/lib/src/lib.rs b/core/lib/src/lib.rs index 069f83d0..bbf10cc3 100644 --- a/core/lib/src/lib.rs +++ b/core/lib/src/lib.rs @@ -6,11 +6,6 @@ #![cfg_attr(nightly, feature(doc_cfg))] #![cfg_attr(nightly, feature(decl_macro))] -#![warn(rust_2018_idioms)] -// #![warn(missing_docs)] -#![allow(async_fn_in_trait)] -#![allow(refining_impl_trait)] - //! # Rocket - Core API Documentation //! //! Hello, and welcome to the core Rocket API documentation! @@ -209,7 +204,7 @@ mod erased; #[doc(inline)] pub use async_trait::async_trait; -const WORKER_PREFIX: &'static str = "rocket-worker"; +const WORKER_PREFIX: &str = "rocket-worker"; /// Creates a [`Rocket`] instance with the default config provider: aliases /// [`Rocket::build()`]. diff --git a/core/lib/src/lifecycle.rs b/core/lib/src/lifecycle.rs index 8439aac7..9859f1f6 100644 --- a/core/lib/src/lifecycle.rs +++ b/core/lib/src/lifecycle.rs @@ -33,7 +33,7 @@ async fn catch_handle(name: Option<&str>, run: F) -> Option } let run = std::panic::AssertUnwindSafe(run); - let fut = std::panic::catch_unwind(move || run()) + let fut = std::panic::catch_unwind(run) .map_err(|e| panic_info!(name, e)) .ok()?; diff --git a/core/lib/src/listener/connection.rs b/core/lib/src/listener/connection.rs index 49d17789..2a3c72c0 100644 --- a/core/lib/src/listener/connection.rs +++ b/core/lib/src/listener/connection.rs @@ -41,7 +41,7 @@ impl Connection for Either { impl Certificates<'_> { pub fn into_owned(self) -> Certificates<'static> { - let cow = self.0.into_iter() + let cow = self.0.iter() .map(|der| der.clone().into_owned()) .collect::>() .into(); diff --git a/core/lib/src/listener/default.rs b/core/lib/src/listener/default.rs index 5732abe0..ffb1f3e0 100644 --- a/core/lib/src/listener/default.rs +++ b/core/lib/src/listener/default.rs @@ -23,7 +23,10 @@ impl DefaultListener { pub(crate) fn base_bindable(&self) -> Result { match &self.address { Endpoint::Tcp(mut address) => { - self.port.map(|port| address.set_port(port)); + if let Some(port) = self.port { + address.set_port(port); + } + Ok(BaseBindable::Left(address)) }, #[cfg(unix)] diff --git a/core/lib/src/listener/endpoint.rs b/core/lib/src/listener/endpoint.rs index e9c45aaa..788c08d0 100644 --- a/core/lib/src/listener/endpoint.rs +++ b/core/lib/src/listener/endpoint.rs @@ -112,10 +112,10 @@ impl Endpoint { pub fn downcast(&self) -> Option<&T> { match self { - Endpoint::Tcp(addr) => (&*addr as &dyn Any).downcast_ref(), - Endpoint::Quic(addr) => (&*addr as &dyn Any).downcast_ref(), - Endpoint::Unix(addr) => (&*addr as &dyn Any).downcast_ref(), - Endpoint::Custom(addr) => (&*addr as &dyn Any).downcast_ref(), + Endpoint::Tcp(addr) => (addr as &dyn Any).downcast_ref(), + Endpoint::Quic(addr) => (addr as &dyn Any).downcast_ref(), + Endpoint::Unix(addr) => (addr as &dyn Any).downcast_ref(), + Endpoint::Custom(addr) => (addr as &dyn Any).downcast_ref(), Endpoint::Tls(inner, ..) => inner.downcast(), } } diff --git a/core/lib/src/listener/tls.rs b/core/lib/src/listener/tls.rs index 1eea9fc1..ceaaa375 100644 --- a/core/lib/src/listener/tls.rs +++ b/core/lib/src/listener/tls.rs @@ -100,7 +100,7 @@ impl Listener for TlsListener type Connection = TlsStream; async fn accept(&self) -> io::Result { - Ok(self.listener.accept().await?) + self.listener.accept().await } async fn connect(&self, conn: L::Connection) -> io::Result { diff --git a/core/lib/src/local/asynchronous/client.rs b/core/lib/src/local/asynchronous/client.rs index e42254b2..68d502e4 100644 --- a/core/lib/src/local/asynchronous/client.rs +++ b/core/lib/src/local/asynchronous/client.rs @@ -92,14 +92,14 @@ impl Client { pub(crate) fn _with_raw_cookies(&self, f: F) -> T where F: FnOnce(&cookie::CookieJar) -> T { - f(&*self.cookies.read()) + f(&self.cookies.read()) } #[inline(always)] pub(crate) fn _with_raw_cookies_mut(&self, f: F) -> T where F: FnOnce(&mut cookie::CookieJar) -> T { - f(&mut *self.cookies.write()) + f(&mut self.cookies.write()) } #[inline(always)] diff --git a/core/lib/src/local/asynchronous/response.rs b/core/lib/src/local/asynchronous/response.rs index 0c3350be..788ed1b8 100644 --- a/core/lib/src/local/asynchronous/response.rs +++ b/core/lib/src/local/asynchronous/response.rs @@ -126,15 +126,15 @@ impl LocalResponse<'_> { } #[cfg(feature = "json")] - async fn _into_json(self) -> Option - where T: serde::de::DeserializeOwned + async fn _into_json(self) -> Option + where T: Send + serde::de::DeserializeOwned + 'static { self.blocking_read(|r| serde_json::from_reader(r)).await?.ok() } #[cfg(feature = "msgpack")] - async fn _into_msgpack(self) -> Option - where T: serde::de::DeserializeOwned + async fn _into_msgpack(self) -> Option + where T: Send + serde::de::DeserializeOwned + 'static { self.blocking_read(|r| rmp_serde::from_read(r)).await?.ok() } @@ -180,7 +180,7 @@ impl LocalResponse<'_> { // TODO: Try to fill as much as the buffer before send it off? let mut buf = Vec::with_capacity(1024); match self.read_buf(&mut buf).await { - Ok(n) if n == 0 => break, + Ok(0) => break, Ok(_) => tx.send(Ok(buf)).await.ok()?, Err(e) => { tx.send(Err(e)).await.ok()?; diff --git a/core/lib/src/local/blocking/response.rs b/core/lib/src/local/blocking/response.rs index fc009398..6f1e3b82 100644 --- a/core/lib/src/local/blocking/response.rs +++ b/core/lib/src/local/blocking/response.rs @@ -56,7 +56,7 @@ pub struct LocalResponse<'c> { impl LocalResponse<'_> { fn _response(&self) -> &Response<'_> { - &self.inner._response() + self.inner._response() } pub(crate) fn _cookies(&self) -> &CookieJar<'_> { diff --git a/core/lib/src/log.rs b/core/lib/src/log.rs index cfd529a2..d49742fc 100644 --- a/core/lib/src/log.rs +++ b/core/lib/src/log.rs @@ -120,7 +120,7 @@ impl log::Log for RocketLogger { // Downgrade a physical launch `warn` to logical `info`. let level = is_launch_record(record.metadata()) - .then(|| log::Level::Info) + .then_some(log::Level::Info) .unwrap_or_else(|| record.level()); match level { diff --git a/core/lib/src/mtls/certificate.rs b/core/lib/src/mtls/certificate.rs index a430b79f..f50f4994 100644 --- a/core/lib/src/mtls/certificate.rs +++ b/core/lib/src/mtls/certificate.rs @@ -126,8 +126,8 @@ impl<'r> FromRequest<'r> for Certificate<'r> { impl<'a> Certificate<'a> { /// PRIVATE: For internal Rocket use only! fn parse<'r>(chain: &'r [CertificateDer<'r>]) -> Result> { - let data = chain.first().ok_or_else(|| Error::Empty)?; - let x509 = Certificate::parse_one(&*data)?; + let data = chain.first().ok_or(Error::Empty)?; + let x509 = Certificate::parse_one(data)?; Ok(Certificate { x509, data }) } @@ -267,7 +267,7 @@ impl<'a> Certificate<'a> { /// } /// ``` pub fn extensions(&self) -> &[x509::X509Extension<'a>] { - &self.inner().extensions() + self.inner().extensions() } /// Checks if the certificate has the serial number `number`. @@ -318,7 +318,7 @@ impl<'a> Certificate<'a> { /// } /// ``` pub fn as_bytes(&self) -> &'a [u8] { - &*self.data + self.data } } diff --git a/core/lib/src/mtls/config.rs b/core/lib/src/mtls/config.rs index 96fc12c9..a1e1e722 100644 --- a/core/lib/src/mtls/config.rs +++ b/core/lib/src/mtls/config.rs @@ -154,7 +154,7 @@ impl MtlsConfig { pub fn ca_certs(&self) -> either::Either { match &self.ca_certs { Either::Left(path) => either::Either::Left(path.relative()), - Either::Right(bytes) => either::Either::Right(&bytes), + Either::Right(bytes) => either::Either::Right(bytes), } } diff --git a/core/lib/src/request/request.rs b/core/lib/src/request/request.rs index 0c92e671..b69b2740 100644 --- a/core/lib/src/request/request.rs +++ b/core/lib/src/request/request.rs @@ -354,7 +354,7 @@ impl<'r> Request<'r> { /// ``` #[inline(always)] pub fn set_remote(&mut self, endpoint: Endpoint) { - self.connection.peer_endpoint = Some(endpoint.into()); + self.connection.peer_endpoint = Some(endpoint); } /// Returns the IP address of the configured @@ -723,7 +723,7 @@ impl<'r> Request<'r> { /// ``` #[inline(always)] pub fn rocket(&self) -> &'r Rocket { - &self.state.rocket + self.state.rocket } /// Returns the configured application data limits. @@ -988,7 +988,7 @@ impl<'r> Request<'r> { pub fn query_value<'a, T>(&'a self, name: &str) -> Option> where T: FromForm<'a> { - if self.query_fields().find(|f| f.name == name).is_none() { + if !self.query_fields().any(|f| f.name == name) { return None; } @@ -1112,7 +1112,7 @@ impl<'r> Request<'r> { }) .unwrap_or_else(|| { errors.push(RequestError::InvalidUri(hyper.uri.clone())); - Origin::ROOT + Origin::root().clone() }); // Construct the request object; fill in metadata and headers next. diff --git a/core/lib/src/response/status.rs b/core/lib/src/response/status.rs index f3abc50c..935fe88f 100644 --- a/core/lib/src/response/status.rs +++ b/core/lib/src/response/status.rs @@ -53,7 +53,7 @@ use crate::http::Status; #[derive(Debug, Clone, PartialEq)] pub struct Created(Cow<'static, str>, Option, Option); -impl<'r, R> Created { +impl Created { /// Constructs a `Created` response with a `location` and no body. /// /// # Example diff --git a/core/lib/src/response/stream/raw_sse.rs b/core/lib/src/response/stream/raw_sse.rs index d0c384d8..6f3bcf57 100644 --- a/core/lib/src/response/stream/raw_sse.rs +++ b/core/lib/src/response/stream/raw_sse.rs @@ -177,11 +177,10 @@ fn skip + Unpin>(buf: &mut Take>) { buf.get_mut().set_position(pos + 1); } } - _ => return, + _ => (), } } - macro_rules! dbg_assert_ready { ($e:expr) => ({ let poll = $e; diff --git a/core/lib/src/rocket.rs b/core/lib/src/rocket.rs index 6d1706e7..bfff32b8 100644 --- a/core/lib/src/rocket.rs +++ b/core/lib/src/rocket.rs @@ -698,7 +698,7 @@ impl Rocket { rocket.shutdown.spawn_listener(&rocket.config.shutdown); if let Err(e) = tokio::spawn(Rocket::liftoff(rocket.clone())).await { - let rocket = rocket.try_wait_shutdown().await; + let rocket = rocket.try_wait_shutdown().await.map(Box::new); return Err(ErrorKind::Liftoff(rocket, Box::new(e)).into()); } @@ -734,7 +734,7 @@ impl Rocket { info!("Shutting down. Waiting for shutdown fairings and pending I/O..."); tokio::spawn({ let rocket = self.clone(); - async move { rocket.fairings.handle_shutdown(&*rocket).await } + async move { rocket.fairings.handle_shutdown(&rocket).await } }); let config = &self.config.shutdown; diff --git a/core/lib/src/router/collider.rs b/core/lib/src/router/collider.rs index d6ada473..1c2aa3a1 100644 --- a/core/lib/src/router/collider.rs +++ b/core/lib/src/router/collider.rs @@ -148,14 +148,14 @@ impl Catcher { impl Collide for Route { #[inline(always)] fn collides_with(&self, other: &Route) -> bool { - Route::collides_with(&self, other) + Route::collides_with(self, other) } } impl Collide for Catcher { #[inline(always)] fn collides_with(&self, other: &Self) -> bool { - Catcher::collides_with(&self, other) + Catcher::collides_with(self, other) } } diff --git a/core/lib/src/router/matcher.rs b/core/lib/src/router/matcher.rs index 00c9dec3..b8468740 100644 --- a/core/lib/src/router/matcher.rs +++ b/core/lib/src/router/matcher.rs @@ -150,10 +150,8 @@ fn paths_match(route: &Route, req: &Request<'_>) -> bool { } // requests with longer paths only match if we have dynamic trail (). - if req_segments.num() > route_segments.len() { - if !route.uri.metadata.dynamic_trail { - return false; - } + if req_segments.num() > route_segments.len() && !route.uri.metadata.dynamic_trail { + return false; } // We've checked everything beyond the zip of their lengths already. diff --git a/core/lib/src/server.rs b/core/lib/src/server.rs index 1f6c0f0c..bb70f5eb 100644 --- a/core/lib/src/server.rs +++ b/core/lib/src/server.rs @@ -47,7 +47,7 @@ impl Rocket { }) ).await; - let io_handler = response.to_io_handler(Rocket::extract_io_handler); + let io_handler = response.make_io_handler(Rocket::extract_io_handler); if let (Some(handler), Some(upgrade)) = (io_handler, upgrade) { let upgrade = upgrade.map_ok(IoStream::from).map_err(io::Error::other); tokio::task::spawn(io_handler_task(upgrade, handler)); @@ -208,7 +208,7 @@ impl Rocket { let meta = ConnectionMeta::from(&conn); let rx = conn.rx.cancellable(rocket.shutdown.clone()); let response = rocket.clone() - .service(conn.parts, rx, None, ConnectionMeta::from(meta)) + .service(conn.parts, rx, None, meta) .map_err(io::Error::other) .io_unless(rocket.shutdown.mercy.clone()) .await?; diff --git a/core/lib/src/shield/policy.rs b/core/lib/src/shield/policy.rs index 29b493c2..ffe66d62 100644 --- a/core/lib/src/shield/policy.rs +++ b/core/lib/src/shield/policy.rs @@ -4,7 +4,6 @@ use std::fmt; use std::borrow::Cow; use indexmap::IndexMap; -use rocket_http::{ext::IntoCollection, private::SmallVec}; use time::Duration; use crate::http::{Header, uri::Absolute, uncased::Uncased}; @@ -410,19 +409,15 @@ impl From<&XssFilter> for Header<'static> { /// that you don't want to leak information to these domains. /// /// [X-DNS-Prefetch-Control]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control +#[derive(Default)] pub enum Prefetch { /// Enables DNS prefetching. This is the browser default. On, /// Disables DNS prefetching. This is the shield policy default. + #[default] Off, } -impl Default for Prefetch { - fn default() -> Prefetch { - Prefetch::Off - } -} - impl From<&Prefetch> for Header<'static> { fn from(prefetch: &Prefetch) -> Self { let policy_string = match prefetch { @@ -475,7 +470,7 @@ impl From<&Prefetch> for Header<'static> { /// /// [Permissions-Policy]: https://github.com/w3c/webappsec-permissions-policy/blob/a45df7b237e2a85e1909d7f226ca4eb4ce5095ba/permissions-policy-explainer.md #[derive(PartialEq, Clone)] -pub struct Permission(IndexMap>>); +pub struct Permission(IndexMap>); impl Default for Permission { /// The default `Permission` policy blocks access to the `interest-cohort` @@ -514,7 +509,7 @@ impl Permission { /// let perm = Permission::allowed(Feature::Usb, [Allow::This, rocket]); /// ``` pub fn allowed(feature: Feature, allow: L) -> Self - where L: IntoCollection + where L: IntoIterator { Permission(IndexMap::new()).allow(feature, allow) } @@ -560,14 +555,9 @@ impl Permission { /// .allow(Feature::Payment, [rocket, Allow::This]); /// ``` pub fn allow(mut self, feature: Feature, allow: L) -> Self - where L: IntoCollection + where L: IntoIterator { - let mut allow = allow.into_collection(); - - if allow.contains(&Allow::Any) { - allow = Allow::Any.into_collection(); - } - + let mut allow: Vec<_> = allow.into_iter().collect(); for allow in &allow { if let Allow::Origin(absolute) = allow { let auth = absolute.authority(); @@ -577,7 +567,11 @@ impl Permission { } } - self.0.insert(feature, Some(allow)); + if allow.contains(&Allow::Any) { + allow = vec![Allow::Any]; + } + + self.0.insert(feature, allow); self } @@ -594,7 +588,7 @@ impl Permission { /// .block(Feature::Payment); /// ``` pub fn block(mut self, feature: Feature) -> Self { - self.0.insert(feature, None); + self.0.insert(feature, vec![]); self } @@ -612,11 +606,11 @@ impl Permission { /// assert_eq!(perm.get(Feature::Usb).unwrap(), &[Allow::Any]); /// ``` pub fn get(&self, feature: Feature) -> Option<&[Allow]> { - self.0.get(&feature)?.as_deref() + Some(self.0.get(&feature)?) } /// Returns an iterator over the pairs of features and their allow lists, - /// `None` if the feature is blocked. + /// empty if the feature is blocked. /// /// Features are returned in the order in which they were first added. /// @@ -635,13 +629,13 @@ impl Permission { /// let perms: Vec<_> = perm.iter().collect(); /// assert_eq!(perms.len(), 3); /// assert_eq!(perms, vec![ - /// (Feature::Camera, Some(&[Allow::Any][..])), - /// (Feature::Gyroscope, Some(&[Allow::This, Allow::Origin(foo)][..])), - /// (Feature::Payment, None), + /// (Feature::Camera, &[Allow::Any][..]), + /// (Feature::Gyroscope, &[Allow::This, Allow::Origin(foo)][..]), + /// (Feature::Payment, &[][..]), /// ]); /// ``` - pub fn iter(&self) -> impl Iterator)> { - self.0.iter().map(|(feature, list)| (*feature, list.as_deref())) + pub fn iter(&self) -> impl Iterator { + self.0.iter().map(|(feature, list)| (*feature, &**list)) } } @@ -658,9 +652,7 @@ impl From<&Permission> for Header<'static> { let value = perm.0.iter() .map(|(feature, allow)| { - let list = allow.as_ref() - .into_iter() - .flatten() + let list = allow.iter() .map(|origin| origin.rendered()) .collect::>() .join(" "); @@ -724,6 +716,16 @@ impl Allow { } } +impl IntoIterator for Allow { + type Item = Self; + + type IntoIter = std::iter::Once; + + fn into_iter(self) -> Self::IntoIter { + std::iter::once(self) + } +} + /// A browser feature that can be enabled or blocked via [`Permission`]. #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] #[non_exhaustive] diff --git a/core/lib/src/tls/config.rs b/core/lib/src/tls/config.rs index 533b5793..c94bb332 100644 --- a/core/lib/src/tls/config.rs +++ b/core/lib/src/tls/config.rs @@ -316,7 +316,7 @@ impl TlsConfig { pub fn certs(&self) -> either::Either { match &self.certs { Either::Left(path) => either::Either::Left(path.relative()), - Either::Right(bytes) => either::Either::Right(&bytes), + Either::Right(bytes) => either::Either::Right(bytes), } } @@ -344,7 +344,7 @@ impl TlsConfig { pub fn key(&self) -> either::Either { match &self.key { Either::Left(path) => either::Either::Left(path.relative()), - Either::Right(bytes) => either::Either::Right(&bytes), + Either::Right(bytes) => either::Either::Right(bytes), } } diff --git a/core/lib/src/util/reader_stream.rs b/core/lib/src/util/reader_stream.rs index da0b1ab0..64775ca6 100644 --- a/core/lib/src/util/reader_stream.rs +++ b/core/lib/src/util/reader_stream.rs @@ -63,7 +63,7 @@ impl ReaderStream { /// [`Stream`]: futures_core::Stream pub fn with_capacity(reader: R, capacity: usize) -> Self { ReaderStream { - reader: reader, + reader, buf: BytesMut::with_capacity(capacity), capacity, done: false, diff --git a/core/lib/tests/catcher-cookies-1213.rs b/core/lib/tests/catcher-cookies-1213.rs index 0b7e81d4..332ee232 100644 --- a/core/lib/tests/catcher-cookies-1213.rs +++ b/core/lib/tests/catcher-cookies-1213.rs @@ -4,7 +4,7 @@ use rocket::request::Request; use rocket::http::CookieJar; #[catch(404)] -fn not_found(request: &Request) -> &'static str { +fn not_found(request: &Request<'_>) -> &'static str { request.cookies().add(("not_found", "404")); "404 - Not Found" } diff --git a/core/lib/tests/config-proxy-proto-header.rs b/core/lib/tests/config-proxy-proto-header.rs index b0ddc014..e601e55c 100644 --- a/core/lib/tests/config-proxy-proto-header.rs +++ b/core/lib/tests/config-proxy-proto-header.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate rocket; #[get("/")] -fn inspect_proto(proto: rocket::http::ProxyProto) -> String { +fn inspect_proto(proto: rocket::http::ProxyProto<'_>) -> String { proto.to_string() } diff --git a/core/lib/tests/form-validation-names.rs b/core/lib/tests/form-validation-names.rs index ccf0e603..e1abe54a 100644 --- a/core/lib/tests/form-validation-names.rs +++ b/core/lib/tests/form-validation-names.rs @@ -68,12 +68,12 @@ fn test_form_validation_context() { count(c, n, kind, false) } - let c = errors::("name=littlebobby"); + let c = errors::>("name=littlebobby"); assert_eq!(exact(&c, "nick", Missing), 1); assert_eq!(fuzzy(&c, "nick", Missing), 1); assert_eq!(fuzzy(&c, "nick", None), 1); - let c = errors::("cats[0].name=Bob"); + let c = errors::>("cats[0].name=Bob"); assert_eq!(exact(&c, "kitty", None), 1); assert_eq!(exact(&c, "kitty", Missing), 1); assert_eq!(exact(&c, "cats[0].nick", None), 1); @@ -91,7 +91,7 @@ fn test_form_validation_context() { assert_eq!(fuzzy(&c, "dog.name", Missing), 1); assert_eq!(fuzzy(&c, "dog", None), 1); - let c = errors::("cats[0].name=Bob&cats[0].nick=kit&kitty.name=Hi"); + let c = errors::>("cats[0].name=Bob&cats[0].nick=kit&kitty.name=Hi"); assert_eq!(exact(&c, "kitty.nick", Missing), 1); assert_eq!(exact(&c, "kitty", None), 0); assert_eq!(exact(&c, "dog", Missing), 1); @@ -109,7 +109,7 @@ fn test_form_validation_context() { assert_eq!(fuzzy(&c, "cats[0].nick", None), 1); assert_eq!(exact(&c, "cats[0].name", None), 1); - let c = errors::("kitty.name=Michael"); + let c = errors::>("kitty.name=Michael"); assert_eq!(exact(&c, "kitty.nick", Missing), 1); assert_eq!(exact(&c, "dog", Missing), 1); assert_eq!(exact(&c, "cats[0].name", None), 0); @@ -125,7 +125,7 @@ fn test_form_validation_context() { assert_eq!(exact(&c, "cats[0].name", None), 0); assert_eq!(exact(&c, "cats[0].nick", None), 0); - let c = errors::("kitty.name=Michael&kitty.nick=kittykat&dog.name=woofy"); + let c = errors::>("kitty.name=Michael&kitty.nick=kittykat&dog.name=woofy"); assert_eq!(c.iter().count(), 1); assert_eq!(exact(&c, "cats", None), 1); assert_eq!(exact(&c, "cats", InvalidLength { min: Some(1), max: None }), 1); diff --git a/core/lib/tests/panic-handling.rs b/core/lib/tests/panic-handling.rs index e2e8e134..f5e8c1ae 100644 --- a/core/lib/tests/panic-handling.rs +++ b/core/lib/tests/panic-handling.rs @@ -73,7 +73,7 @@ fn catches_early_route_panic() { #[test] fn catches_early_catcher_panic() { - fn pre_future_catcher<'r>(_: Status, _: &'r Request) -> catcher::BoxFuture<'r> { + fn pre_future_catcher<'r>(_: Status, _: &'r Request<'_>) -> catcher::BoxFuture<'r> { panic!("a panicking pre-future catcher") } diff --git a/core/lib/tests/responder_lifetime-issue-345.rs b/core/lib/tests/responder_lifetime-issue-345.rs index ce7305f4..4cd12f00 100644 --- a/core/lib/tests/responder_lifetime-issue-345.rs +++ b/core/lib/tests/responder_lifetime-issue-345.rs @@ -19,11 +19,11 @@ impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for CustomResponder<'r, } #[get("/unit_state")] -fn unit_state(state: &State) -> CustomResponder<()> { +fn unit_state(state: &State) -> CustomResponder<'_, ()> { CustomResponder { responder: (), state: &*state } } #[get("/string_state")] -fn string_state(state: &State) -> CustomResponder { +fn string_state(state: &State) -> CustomResponder<'_, String> { CustomResponder { responder: "".to_string(), state: &*state } } diff --git a/examples/chat/src/tests.rs b/examples/chat/src/tests.rs index 0b77ef76..91ceb1a6 100644 --- a/examples/chat/src/tests.rs +++ b/examples/chat/src/tests.rs @@ -77,7 +77,7 @@ async fn messages() { } let data: Message = json::from_str(&line[5..]).expect("message JSON"); - if &data == &shutdown_message { + if data == shutdown_message { // Test shutdown listening: this should end the stream. client.rocket().shutdown().notify(); continue; diff --git a/examples/config/src/tests.rs b/examples/config/src/tests.rs index e774f7ec..c8351ed2 100644 --- a/examples/config/src/tests.rs +++ b/examples/config/src/tests.rs @@ -4,7 +4,7 @@ async fn test_config(profile: &str) { let provider = Config::figment().select(profile); let rocket = rocket::custom(provider).ignite().await.unwrap(); let config = rocket.config(); - match &*profile { + match profile { "debug" => { assert_eq!(config.workers, 1); assert_eq!(config.keep_alive, 0); diff --git a/examples/cookies/src/session.rs b/examples/cookies/src/session.rs index 11bf55d1..31d0fc61 100644 --- a/examples/cookies/src/session.rs +++ b/examples/cookies/src/session.rs @@ -54,7 +54,7 @@ fn login(_user: User) -> Redirect { #[get("/login", rank = 2)] fn login_page(flash: Option>) -> Template { - Template::render("login", &flash) + Template::render("login", flash) } #[post("/login", data = "")] diff --git a/examples/cookies/src/tests.rs b/examples/cookies/src/tests.rs index b6c3e047..7a855874 100644 --- a/examples/cookies/src/tests.rs +++ b/examples/cookies/src/tests.rs @@ -5,8 +5,7 @@ use rocket::http::{Status, Cookie, ContentType}; fn user_id_cookie(response: &LocalResponse<'_>) -> Option> { let cookie = response.headers() .get("Set-Cookie") - .filter(|v| v.starts_with("user_id")) - .nth(0) + .find(|v| v.starts_with("user_id")) .and_then(|val| Cookie::parse_encoded(val).ok()); cookie.map(|c| c.into_owned()) diff --git a/examples/databases/src/diesel_mysql.rs b/examples/databases/src/diesel_mysql.rs index 19d6132e..2d5a9a56 100644 --- a/examples/databases/src/diesel_mysql.rs +++ b/examples/databases/src/diesel_mysql.rs @@ -80,7 +80,7 @@ async fn delete(mut db: Connection, id: i64) -> Result> { .execute(&mut db) .await?; - Ok((affected == 1).then(|| ())) + Ok((affected == 1).then_some(())) } #[delete("/")] diff --git a/examples/databases/src/diesel_sqlite.rs b/examples/databases/src/diesel_sqlite.rs index 8e5a9da4..ce14c913 100644 --- a/examples/databases/src/diesel_sqlite.rs +++ b/examples/databases/src/diesel_sqlite.rs @@ -73,7 +73,7 @@ async fn delete(db: Db, id: i32) -> Result> { .execute(conn) }).await?; - Ok((affected == 1).then(|| ())) + Ok((affected == 1).then_some(())) } #[delete("/")] diff --git a/examples/databases/src/rusqlite.rs b/examples/databases/src/rusqlite.rs index 92674e27..d4a94a5a 100644 --- a/examples/databases/src/rusqlite.rs +++ b/examples/databases/src/rusqlite.rs @@ -61,7 +61,7 @@ async fn delete(db: Db, id: i64) -> Result> { conn.execute("DELETE FROM posts WHERE id = ?1", params![id]) }).await?; - Ok((affected == 1).then(|| ())) + Ok((affected == 1).then_some(())) } #[delete("/")] diff --git a/examples/databases/src/sqlx.rs b/examples/databases/src/sqlx.rs index c52cc2e7..de9c5192 100644 --- a/examples/databases/src/sqlx.rs +++ b/examples/databases/src/sqlx.rs @@ -3,7 +3,7 @@ use rocket::fairing::{self, AdHoc}; use rocket::response::status::Created; use rocket::serde::{Serialize, Deserialize, json::Json}; -use rocket_db_pools::{sqlx, Database, Connection}; +use rocket_db_pools::{Database, Connection}; use futures::{stream::TryStreamExt, future::TryFutureExt}; @@ -63,7 +63,7 @@ async fn delete(mut db: Connection, id: i64) -> Result> { .execute(&mut **db) .await?; - Ok((result.rows_affected() == 1).then(|| ())) + Ok((result.rows_affected() == 1).then_some(())) } #[delete("/")] diff --git a/examples/databases/src/tests.rs b/examples/databases/src/tests.rs index e2e6aeed..a2690c11 100644 --- a/examples/databases/src/tests.rs +++ b/examples/databases/src/tests.rs @@ -46,7 +46,7 @@ fn test(base: &str, stage: AdHoc) { for _ in 1..=N { // Get a valid ID from the index. let list = client.get(base).dispatch().into_json::>().unwrap(); - let id = list.get(0).expect("have post"); + let id = list.first().expect("have post"); // Delete that post. let response = client.delete(format!("{}/{}", base, id)).dispatch(); diff --git a/examples/error-handling/src/tests.rs b/examples/error-handling/src/tests.rs index 585913e1..fcd78424 100644 --- a/examples/error-handling/src/tests.rs +++ b/examples/error-handling/src/tests.rs @@ -10,7 +10,7 @@ fn test_hello() { let response = client.get(uri).dispatch(); assert_eq!(response.status(), Status::Ok); - assert_eq!(response.into_string().unwrap(), super::hello(name.into(), age)); + assert_eq!(response.into_string().unwrap(), super::hello(name, age)); } #[test] @@ -54,7 +54,8 @@ fn test_hello_invalid_age() { assert_eq!(response.into_string().unwrap(), expected.1); } - for path in &["foo/bar/baz"] { + { + let path = &"foo/bar/baz"; let request = client.get(format!("/hello/{}", path)); let expected = super::hello_not_found(request.inner()); let response = request.dispatch(); diff --git a/examples/manual-routing/src/tests.rs b/examples/manual-routing/src/tests.rs index 578a076a..736157af 100644 --- a/examples/manual-routing/src/tests.rs +++ b/examples/manual-routing/src/tests.rs @@ -1,6 +1,6 @@ use super::*; use rocket::local::blocking::Client; -use rocket::http::{ContentType, Status}; +use rocket::http::ContentType; fn test(uri: &str, content_type: ContentType, status: Status, body: String) { let client = Client::tracked(rocket()).unwrap(); @@ -24,7 +24,7 @@ fn test_name() { #[test] fn test_echo() { - let uri = format!("/echo/echo%20this%20text"); + let uri = "/echo/echo%20this%20text".to_string(); test(&uri, ContentType::Plain, Status::Ok, "echo this text".into()); } diff --git a/examples/pastebin/src/paste_id.rs b/examples/pastebin/src/paste_id.rs index 2213a019..3f31a67b 100644 --- a/examples/pastebin/src/paste_id.rs +++ b/examples/pastebin/src/paste_id.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::path::{Path, PathBuf}; -use rand::{self, Rng}; +use rand::Rng; use rocket::request::FromParam; /// A _probably_ unique paste ID. diff --git a/examples/state/src/tests.rs b/examples/state/src/tests.rs index 0a3debb7..2ff35a73 100644 --- a/examples/state/src/tests.rs +++ b/examples/state/src/tests.rs @@ -7,7 +7,7 @@ fn test_count() { fn get_count(client: &Client) -> usize { let response = client.get("/count").dispatch().into_string().unwrap(); - let count = response.split(" ").last().unwrap(); + let count = response.split(' ').last().unwrap(); count.parse().unwrap() } diff --git a/examples/static-files/src/tests.rs b/examples/static-files/src/tests.rs index df096dc6..59c0ceca 100644 --- a/examples/static-files/src/tests.rs +++ b/examples/static-files/src/tests.rs @@ -16,17 +16,16 @@ fn test_query_file (path: &str, file: T, status: Status) let body_data = response.into_bytes(); if let Some(filename) = file.into() { - let expected_data = read_file_content(filename); + let expected_data = read_file_content(filename).expect(filename); assert!(body_data.map_or(false, |s| s == expected_data)); } } -fn read_file_content(path: &str) -> Vec { - let mut fp = File::open(&path).expect(&format!("Can't open {}", path)); +fn read_file_content(path: &str) -> std::io::Result> { let mut file_content = vec![]; - - fp.read_to_end(&mut file_content).expect(&format!("Reading {} failed.", path)); - file_content + let mut fp = File::open(path)?; + fp.read_to_end(&mut file_content)?; + Ok(file_content) } #[test] diff --git a/examples/tls/src/redirector.rs b/examples/tls/src/redirector.rs index fb42ac7b..43892108 100644 --- a/examples/tls/src/redirector.rs +++ b/examples/tls/src/redirector.rs @@ -91,7 +91,7 @@ impl Fairing for Redirector { let this = *self; let shutdown = rocket.shutdown(); - let _ = rocket::tokio::spawn(async move { + rocket::tokio::spawn(async move { if let Err(e) = this.try_launch(config).await { error!("Failed to start HTTP -> HTTPS redirector."); info_!("Error: {}", e); diff --git a/examples/todo/src/task.rs b/examples/todo/src/task.rs index eb93ffe7..0f45168a 100644 --- a/examples/todo/src/task.rs +++ b/examples/todo/src/task.rs @@ -1,5 +1,5 @@ use rocket::serde::Serialize; -use diesel::{self, result::QueryResult, prelude::*}; +use diesel::{self, prelude::*}; mod schema { table! { diff --git a/examples/todo/src/tests.rs b/examples/todo/src/tests.rs index 5c2eadd7..04b90339 100644 --- a/examples/todo/src/tests.rs +++ b/examples/todo/src/tests.rs @@ -54,7 +54,7 @@ fn test_insertion_deletion() { // Ensure the task is what we expect. assert_eq!(new_tasks[0].description, "My first task"); - assert_eq!(new_tasks[0].completed, false); + assert!(!new_tasks[0].completed); // Issue a request to delete the task. let id = new_tasks[0].id.unwrap(); @@ -63,7 +63,7 @@ fn test_insertion_deletion() { // Ensure it's gone. let final_tasks = Task::all(&conn).await.unwrap(); assert_eq!(final_tasks.len(), init_tasks.len()); - if final_tasks.len() > 0 { + if !final_tasks.is_empty() { assert_ne!(final_tasks[0].description, "My first task"); } }) @@ -80,15 +80,15 @@ fn test_toggle() { .await; let task = Task::all(&conn).await.unwrap()[0].clone(); - assert_eq!(task.completed, false); + assert!(!task.completed); // Issue a request to toggle the task; ensure it is completed. client.put(format!("/todo/{}", task.id.unwrap())).dispatch().await; - assert_eq!(Task::all(&conn).await.unwrap()[0].completed, true); + assert!(Task::all(&conn).await.unwrap()[0].completed); // Issue a request to toggle the task; ensure it's not completed again. client.put(format!("/todo/{}", task.id.unwrap())).dispatch().await; - assert_eq!(Task::all(&conn).await.unwrap()[0].completed, false); + assert!(!Task::all(&conn).await.unwrap()[0].completed); }) }