Skip to content

Commit

Permalink
Improve must_use diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
novacrazy committed Sep 13, 2024
1 parent 7a437ea commit efb4288
Show file tree
Hide file tree
Showing 24 changed files with 91 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/api/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ macro_rules! command {
#[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))]
#[cfg_attr(feature = "bon", derive(bon::Builder))]
#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[must_use = "Commands do nothing unless executed via a `Driver`."]
$(#[$($meta)*])*
pub struct $name {
$($(#[$($field_meta)*])* $field_vis $field_name: $field_ty, )*
Expand Down
2 changes: 2 additions & 0 deletions src/api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct ApiError {
impl ArchivedApiError {
/// Get the error code for this error.
#[inline]
#[must_use]
pub const fn code(&self) -> ApiErrorCode {
self.code.get()
}
Expand Down Expand Up @@ -58,6 +59,7 @@ macro_rules! error_codes {

impl $name {
/// Get the HTTP status code for this error code.
#[must_use]
pub fn http_status(self) -> StatusCode {
match self {
$(Self::$variant => $status,)*
Expand Down
2 changes: 2 additions & 0 deletions src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct ClientInner {
preferred_encoding: ArcSwap<Encoding>,
}

#[must_use = "Client does nothing on its own."]
#[derive(Clone)]
pub struct Client(Arc<ClientInner>);

Expand Down Expand Up @@ -63,6 +64,7 @@ impl Client {
Ok(())
}

#[must_use]
pub fn auth(&self) -> Option<AuthToken> {
self.0.auth.load().as_ref().map(|auth| auth.0)
}
Expand Down
1 change: 1 addition & 0 deletions src/driver/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub enum DriverError {
}

impl DriverError {
#[must_use]
pub fn is_not_found(&self) -> bool {
match self {
DriverError::ApiError(err) => err.code == ApiErrorCode::NotFound,
Expand Down
1 change: 1 addition & 0 deletions src/driver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub enum Encoding {
CBOR,
}

#[must_use = "This struct does nothing on its own. Use `Driver::execute` to send a request."]
#[derive(Clone)]
pub struct Driver {
pub(crate) inner: reqwest::Client,
Expand Down
1 change: 1 addition & 0 deletions src/framework/standard/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ impl StandardContext {
self.client().driver()
}

#[must_use]
pub fn close(&self) -> bool {
self.inner().tx.send(StandardResponse::Close).is_ok()
}
Expand Down
1 change: 1 addition & 0 deletions src/framework/standard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub struct Standard<H, E: StandardErrorExt = StandardError> {
}

impl<E: StandardErrorExt> Standard<StandardDynamicHandler<(), E>, E> {
#[must_use]
pub fn new(client: Client) -> Self {
Self::new_with_state(client, ())
}
Expand Down
11 changes: 11 additions & 0 deletions src/framework_utils/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,30 +42,37 @@ impl<'a> Argument<'a> {
}
}

#[must_use]
pub fn orig(&self) -> &'a str {
self.buf
}

#[must_use]
pub fn inner_str(&self) -> &'a str {
&self.buf[self.inner()]
}

#[must_use]
pub fn outer_str(&self) -> &'a str {
&self.buf[self.outer()]
}

#[must_use]
pub fn inner(&self) -> Range<usize> {
self.inner_start..self.inner_end
}

#[must_use]
pub fn outer(&self) -> Range<usize> {
self.outer_start..self.outer_end
}

#[must_use]
pub fn is_quoted(&self) -> bool {
self.inner() != self.outer()
}

#[must_use]
pub fn is_quoted_with(&self, (start, end): (char, char)) -> bool {
let outer = self.outer_str();

Expand All @@ -74,10 +81,12 @@ impl<'a> Argument<'a> {
}

impl<'a> ArgumentSplitter<'a> {
#[must_use]
pub fn orig(&self) -> &'a str {
self.buf
}

#[must_use]
pub fn arguments(&self) -> &[Argument<'a>] {
&self.arguments
}
Expand All @@ -89,10 +98,12 @@ impl<'a> ArgumentSplitter<'a> {
self.arguments.iter().map(|r| r.inner_str())
}

#[must_use]
pub fn split(args: &'a str) -> Self {
Self::split_delimiters(args, &[('`', '`'), ('"', '"'), ('\u{201C}', '\u{201D}')])
}

#[must_use]
pub fn split_delimiters(args: &'a str, delmiters: &[(char, char)]) -> Self {
let buf = args;
let mut arguments = SmallVec::new();
Expand Down
1 change: 1 addition & 0 deletions src/gateway/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ impl GatewayConnectionControl {
}

impl GatewayConnection {
#[must_use]
pub fn new(client: Client) -> GatewayConnection {
GatewayConnection {
client,
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Lantern Chat Client SDK

//#![cfg_attr(not(feature = "std"), no_std)]
#![warn(clippy::perf, clippy::must_use_candidate, clippy::complexity, clippy::suspicious)]
#![allow(clippy::bad_bit_mask)]

extern crate alloc;
Expand Down
4 changes: 4 additions & 0 deletions src/models/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ impl_sql_for_bitflags!(AssetFlags);

impl AssetFlags {
/// Sets the quality of the asset, clamping to `[0-128)`
#[must_use]
pub const fn with_quality(self, q: u8) -> Self {
self.intersection(Self::QUALITY.complement()).union(if q < 128 {
AssetFlags::from_bits_truncate(q as i16)
Expand All @@ -70,6 +71,7 @@ impl AssetFlags {
}

/// Sets the alpha channel flag
#[must_use]
pub const fn with_alpha(&self, has_alpha: bool) -> Self {
if has_alpha {
self.union(Self::HAS_ALPHA)
Expand All @@ -79,11 +81,13 @@ impl AssetFlags {
}

/// Gets the quality value from the asset flags
#[must_use]
pub const fn quality(&self) -> u8 {
self.intersection(Self::QUALITY).bits() as u8
}

/// Constructs a new `AssetFlags` from the given extension
#[must_use]
pub fn from_ext(ext: &str) -> Self {
static FORMAT_EXTS: &[(AssetFlags, &str)] = &[
(AssetFlags::FORMAT_PNG, "png"),
Expand Down
1 change: 1 addition & 0 deletions src/models/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ impl fmt::Display for InvalidAuthToken {
impl core::error::Error for InvalidAuthToken {}

impl AuthToken {
#[must_use]
pub fn raw_header(&self) -> arrayvec::ArrayString<{ MAX_LENGTH }> {
let (prefix, value) = match self {
AuthToken::Bearer(ref token) => (BEARER_PREFIX, token.as_ref()),
Expand Down
1 change: 1 addition & 0 deletions src/models/embed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod v1;
pub use v1::*;

impl Embed {
#[must_use]
pub fn url(&self) -> Option<&str> {
match self {
Embed::V1(embed) => embed.url.as_ref().map(|x| x as _),
Expand Down
6 changes: 6 additions & 0 deletions src/models/embed/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ pub struct EmbedV1 {
}

impl EmbedV1 {
#[must_use]
pub fn has_fullsize_media(&self) -> bool {
!EmbedMedia::is_empty(&self.obj)
|| !EmbedMedia::is_empty(&self.img)
Expand All @@ -192,6 +193,7 @@ impl EmbedV1 {
}

// NOTE: Provider, canonical, and title can be skipped here, as by themselves it's a very boring embed
#[must_use]
pub fn is_plain_link(&self) -> bool {
if self.ty != EmbedType::Link
|| self.url.is_none()
Expand Down Expand Up @@ -528,6 +530,7 @@ impl EmbedMedia {
}
}

#[must_use]
pub fn is_empty(this: &Option<Box<EmbedMedia>>) -> bool {
match this {
Some(ref e) => e.url.is_empty(),
Expand Down Expand Up @@ -570,12 +573,14 @@ pub struct EmbedProvider {
}

impl EmbedProvider {
#[must_use]
pub fn is_none(&self) -> bool {
is_none_or_empty(&self.name) && IsNoneOrEmpty::is_none_or_empty(&self.url) && EmbedMedia::is_empty(&self.icon)
}
}

impl EmbedAuthor {
#[must_use]
pub fn is_none(this: &Option<Self>) -> bool {
match this {
Some(ref this) => {
Expand Down Expand Up @@ -644,6 +649,7 @@ pub struct EmbedField {
}

impl EmbedField {
#[must_use]
pub fn is_empty(&self) -> bool {
(self.name.is_empty() || self.value.is_empty()) && EmbedMedia::is_empty(&self.img)
}
Expand Down
8 changes: 5 additions & 3 deletions src/models/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ pub mod message {
}
}

#[inline(always)]
#[inline(always)] #[must_use]
pub fn state(&self) -> &S {
&self.state
}
Expand Down Expand Up @@ -486,6 +486,7 @@ pub mod message {

impl $name {
/// Returns the discrete opcode for the message
#[must_use]
pub const fn opcode(&self) -> [<$name Opcode>] {
match self {
$($name::$opcode(_) => [<$name Opcode>]::$opcode,)*
Expand All @@ -505,7 +506,7 @@ pub mod message {
#[doc = "Create new [`" $opcode "`](" $name "::" $opcode ") message from payload fields."]
#[doc = ""]
$(#[$variant_meta])*
#[inline]
#[inline] #[must_use]
pub fn [<new_ $opcode:snake>]($($field: impl Into<$ty>),*) -> Self {
$name::$opcode([<$name:snake _payloads>]::[<$opcode Payload>] {
$($field: $field.into()),*
Expand Down Expand Up @@ -695,7 +696,7 @@ pub mod message {
}

impl ServerMsg {
#[rustfmt::skip]
#[rustfmt::skip] #[must_use]
pub fn matching_intent(&self) -> Option<Intent> {
Some(match *self {
| ServerMsg::PartyCreate { .. }
Expand Down Expand Up @@ -753,6 +754,7 @@ pub mod message {
}

/// If the event originated from a specific user, get their ID
#[must_use]
pub fn user_id(&self) -> Option<UserId> {
Some(match self {
ServerMsg::MemberAdd(e) => e.member.user.id,
Expand Down
1 change: 1 addition & 0 deletions src/models/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ impl_sql_for_bitflags!(MessageFlags);

impl MessageFlags {
#[inline]
#[must_use]
pub const fn from_bits_truncate_public(bits: i32) -> Self {
Self::from_bits_truncate(bits).difference(Self::LANGUAGE)
}
Expand Down
14 changes: 13 additions & 1 deletion src/models/nullable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
///
/// Similarly, not all gateway events provide all information in objects. Again, user profiles
/// are notable in that biographies are typically excluded in events to save on bandwidth.
#[must_use = "This enum is used to represent nullable values, and should be used as such"]
#[derive(Default, Debug, Clone, Copy, Hash)]
#[repr(u8)]
pub enum Nullable<T> {
Expand Down Expand Up @@ -79,6 +80,7 @@ impl<T> Nullable<T> {
}

/// Converts `Nullable<T>` to `Nullable<&T>`.
#[inline]
pub fn as_ref(&self) -> Nullable<&T> {
match self {
Nullable::Some(value) => Nullable::Some(value),
Expand All @@ -87,10 +89,20 @@ impl<T> Nullable<T> {
}
}

/// Converts `Nullable<T>` to `Nullable<&mut T>`.
#[inline]
pub fn as_mut(&mut self) -> Nullable<&mut T> {
match self {
Nullable::Some(value) => Nullable::Some(value),
Nullable::Null => Nullable::Null,
Nullable::Undefined => Nullable::Undefined,
}
}

/// Maps an inner `Some` value to a different value, using `Into`.
///
/// Equivalent to `.map(Into::into)`.
pub fn map_into<U>(self) -> Nullable<U>
pub fn convert<U>(self) -> Nullable<U>
where
T: Into<U>,
{
Expand Down
9 changes: 9 additions & 0 deletions src/models/permission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ impl Overwrite {
///
/// With debug assertions enabled, this function will panic if the IDs do not match.
#[inline]
#[must_use]
pub const fn combine(&self, other: Self) -> Overwrite {
//debug_assert_eq!(self.id, other.id);
#[cfg(debug_assertions)]
Expand All @@ -229,6 +230,7 @@ impl Overwrite {
///
/// Equivalent to `(base & !deny) | allow`.
#[inline]
#[must_use]
pub const fn apply(&self, base: Permissions) -> Permissions {
// self.allow(base & !self.deny) | self.allow
base.difference(self.deny).union(self.allow)
Expand All @@ -238,12 +240,14 @@ impl Overwrite {
impl Permissions {
/// Constructs a new `Permissions` from two `i64` values.
#[inline(always)]
#[must_use]
pub const fn from_i64(low: i64, high: i64) -> Self {
Permissions::from_bits_truncate(low as u64 as u128 | ((high as u64 as u128) << 64))
}

/// Constructs a new `Permissions` from two `Option<i64>` values, defaulting to `0` if `None` on either.
#[inline(always)]
#[must_use]
pub const fn from_i64_opt(low: Option<i64>, high: Option<i64>) -> Self {
// TODO: Replace with `.unwrap_or(0)` when that's const-stable
Permissions::from_i64(
Expand All @@ -260,6 +264,7 @@ impl Permissions {

/// Converts the `Permissions` into two `i64` values.
#[inline(always)]
#[must_use]
pub const fn to_i64(self) -> [i64; 2] {
let bits = self.bits();
let low = bits as u64 as i64;
Expand All @@ -268,11 +273,14 @@ impl Permissions {
}

/// Returns `true` if the permissions contain the `ADMINISTRATOR` permission.
#[inline(always)]
#[must_use]
pub const fn is_admin(self) -> bool {
self.contains(Permissions::ADMINISTRATOR)
}

/// Takes cerrtain flags into account and normalizes the permissions to obey them.
#[must_use]
pub const fn normalize(self) -> Self {
if self.contains(Permissions::DEFAULT_ONLY) {
return Permissions::DEFAULT;
Expand All @@ -286,6 +294,7 @@ impl Permissions {
}

/// Computes the final permissions for a user in a room given the overwrites and roles.
#[must_use]
pub fn compute_overwrites(mut self, overwrites: &[Overwrite], user_roles: &[RoleId], user_id: UserId) -> Permissions {
if self.contains(Permissions::ADMINISTRATOR) {
return Permissions::all();
Expand Down
Loading

0 comments on commit efb4288

Please sign in to comment.