Skip to content

Commit

Permalink
Use ArrayString in more places via aformat! (serenity-rs#2902)
Browse files Browse the repository at this point in the history
This also bumps `to-arraystring` up to 0.2, required for `aformat`.
  • Loading branch information
GnomedDev committed Nov 11, 2024
1 parent c1e8f31 commit ed38462
Show file tree
Hide file tree
Showing 13 changed files with 92 additions and 50 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ name: CI
on: [push, pull_request]

env:
rust_min: 1.74.0
rust_nightly: nightly-2024-03-09
rust_min: 1.79.0
rust_nightly: nightly-2024-06-21

jobs:
test:
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ readme = "README.md"
repository = "https://github.com/serenity-rs/serenity.git"
version = "0.12.2"
edition = "2021"
rust-version = "1.74"
rust-version = "1.79"
include = ["src/**/*", "LICENSE.md", "README.md", "CHANGELOG.md", "build.rs"]

[workspace]
Expand All @@ -36,8 +36,9 @@ small-fixed-array = { version = "0.4", features = ["serde"] }
bool_to_bitflags = { version = "0.1.2" }
nonmax = { version = "0.5.5", features = ["serde"] }
strum = { version = "0.26", features = ["derive"] }
to-arraystring = "0.1.0"
to-arraystring = "0.2.0"
extract_map = { version = "0.1.0", features = ["serde", "iter_mut"] }
aformat = "0.1.3"
# Optional dependencies
fxhash = { version = "0.2.1", optional = true }
chrono = { version = "0.4.31", default-features = false, features = ["clock", "serde"], optional = true }
Expand Down
1 change: 0 additions & 1 deletion src/builder/bot_auth_parameters.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::borrow::Cow;

use arrayvec::ArrayVec;
use to_arraystring::ToArrayString;
use url::Url;

#[cfg(feature = "http")]
Expand Down
7 changes: 3 additions & 4 deletions src/gateway/shard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -771,10 +771,9 @@ impl Shard {
}

async fn connect(base_url: &str) -> Result<WsClient> {
let url =
Url::parse(&format!("{base_url}?v={}", constants::GATEWAY_VERSION)).map_err(|why| {
warn!("Error building gateway URL with base `{}`: {:?}", base_url, why);

let url = Url::parse(&aformat!("{}?v={}", CapStr::<64>(base_url), constants::GATEWAY_VERSION))
.map_err(|why| {
warn!("Error building gateway URL with base `{base_url}`: {why:?}");
Error::Gateway(GatewayError::BuildingUrl)
})?;

Expand Down
2 changes: 1 addition & 1 deletion src/http/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ fn parse_token(token: &str) -> Arc<str> {
if token.starts_with("Bot ") || token.starts_with("Bearer ") {
Arc::from(token)
} else {
Arc::from(format!("Bot {token}"))
Arc::from(aformat!("Bot {}", CapStr::<128>(token)).as_str())
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/internal/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

pub use std::result::Result as StdResult;

pub use aformat::{aformat, aformat_into, ArrayString, CapStr};
pub use extract_map::{ExtractKey, ExtractMap, LendingIterator};
pub use serde_json::Value;
pub use small_fixed_array::{FixedArray, FixedString, TruncatingInto};
pub use to_arraystring::ToArrayString;

pub(crate) use super::utils::join_to_string;
pub use crate::error::{Error, Result};
Expand Down
4 changes: 4 additions & 0 deletions src/model/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use serde::de::Error;
use to_arraystring::ToArrayString;

use super::prelude::*;
use super::Timestamp;
use crate::internal::prelude::*;

macro_rules! newtype_display_impl {
($name:ident, |$this:ident| $inner:expr) => {
Expand Down Expand Up @@ -120,6 +122,8 @@ macro_rules! id_u64 {

impl ToArrayString for $name {
type ArrayString = <u64 as ToArrayString>::ArrayString;
const MAX_LENGTH: usize = <u64 as ToArrayString>::MAX_LENGTH;

fn to_arraystring(self) -> Self::ArrayString {
self.get().to_arraystring()
}
Expand Down
20 changes: 8 additions & 12 deletions src/model/mention.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ use std::fmt;
#[cfg(all(feature = "model", feature = "utils"))]
use std::str::FromStr;

use to_arraystring::ToArrayString;

use super::prelude::*;
use crate::internal::prelude::*;
#[cfg(all(feature = "model", feature = "utils"))]
use crate::utils;

Expand Down Expand Up @@ -113,19 +112,16 @@ impl fmt::Display for Mention {
}

impl ToArrayString for Mention {
type ArrayString = arrayvec::ArrayString<{ 20 + 4 }>;
const MAX_LENGTH: usize = 20 + 4;
type ArrayString = ArrayString<{ 20 + 4 }>;

fn to_arraystring(self) -> Self::ArrayString {
let (prefix, id) = match self {
Self::Channel(id) => ("<#", id.get()),
Self::Role(id) => ("<@&", id.get()),
Self::User(id) => ("<@", id.get()),
};

let mut out = Self::ArrayString::new();
out.push_str(prefix);
out.push_str(&id.to_arraystring());
out.push('>');
match self {
Self::Channel(id) => aformat_into!(out, "<#{id}>"),
Self::Role(id) => aformat_into!(out, "<@&{id}>"),
Self::User(id) => aformat_into!(out, "<@{id}>"),
};

out
}
Expand Down
2 changes: 0 additions & 2 deletions src/model/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ use std::fmt::Write;
use std::result::Result as StdResult;
use std::str::FromStr;

use arrayvec::ArrayString;

use super::prelude::*;
use crate::internal::prelude::*;
#[cfg(all(feature = "model", any(feature = "cache", feature = "utils")))]
Expand Down
7 changes: 5 additions & 2 deletions src/utils/argument_convert/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use role::*;
mod emoji;
pub use emoji::*;

use super::DOMAINS;
use super::{DOMAINS, MAX_DOMAIN_LEN};
use crate::model::prelude::*;
use crate::prelude::*;

Expand Down Expand Up @@ -124,8 +124,11 @@ pub fn parse_message_id_pair(s: &str) -> Option<(ChannelId, MessageId)> {
/// ```
#[must_use]
pub fn parse_message_url(s: &str) -> Option<(GuildId, ChannelId, MessageId)> {
use aformat::{aformat, CapStr};

for domain in DOMAINS {
if let Some(parts) = s.strip_prefix(&format!("https://{domain}/channels/")) {
let prefix = aformat!("https://{}/channels/", CapStr::<MAX_DOMAIN_LEN>(domain));
if let Some(parts) = s.strip_prefix(prefix.as_str()) {
let mut parts = parts.splitn(3, '/');

let guild_id = parts.next()?.parse().ok()?;
Expand Down
68 changes: 47 additions & 21 deletions src/utils/formatted_timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use std::error::Error as StdError;
use std::fmt;
use std::str::FromStr;

use aformat::{ArrayString, ToArrayString};

use crate::all::Timestamp;
use crate::internal::prelude::*;

/// Represents a combination of a timestamp and a style for formatting time in messages.
///
Expand Down Expand Up @@ -81,17 +84,33 @@ impl From<Timestamp> for FormattedTimestamp {
}
}

impl fmt::Display for FormattedTimestamp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.style {
Some(style) => write!(f, "<t:{}:{}>", self.timestamp, style),
None => write!(f, "<t:{}>", self.timestamp),
impl ToArrayString for FormattedTimestamp {
const MAX_LENGTH: usize = 27;
type ArrayString = ArrayString<27>;

fn to_arraystring(self) -> Self::ArrayString {
let mut out = Self::ArrayString::new();
if let Some(style) = self.style {
aformat_into!(out, "<t:{}:{}>", self.timestamp, style);
} else {
aformat_into!(out, "<t:{}>", self.timestamp);
}

out
}
}

impl fmt::Display for FormattedTimestampStyle {
impl fmt::Display for FormattedTimestamp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_arraystring())
}
}

impl ToArrayString for FormattedTimestampStyle {
const MAX_LENGTH: usize = 1;
type ArrayString = ArrayString<1>;

fn to_arraystring(self) -> Self::ArrayString {
let style = match self {
Self::ShortTime => "t",
Self::LongTime => "T",
Expand All @@ -101,7 +120,15 @@ impl fmt::Display for FormattedTimestampStyle {
Self::LongDateTime => "F",
Self::RelativeTime => "R",
};
f.write_str(style)

ArrayString::from(style)
.expect("One ASCII character should fit into an ArrayString of one capacity")
}
}

impl fmt::Display for FormattedTimestampStyle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_arraystring())
}
}

Expand Down Expand Up @@ -175,12 +202,11 @@ mod tests {
let timestamp = Timestamp::now();

let time = FormattedTimestamp::new(timestamp, Some(FormattedTimestampStyle::ShortDateTime));

let time_str = time.to_string();
let time_str = time.to_arraystring();

assert_eq!(
time_str,
format!(
aformat!(
"<t:{}:{}>",
timestamp.unix_timestamp(),
FormattedTimestampStyle::ShortDateTime
Expand All @@ -189,20 +215,20 @@ mod tests {

let unstyled = FormattedTimestamp::new(timestamp, None);

let unstyled_str = unstyled.to_string();
let unstyled_str = unstyled.to_arraystring();

assert_eq!(unstyled_str, format!("<t:{}>", timestamp.unix_timestamp()));
assert_eq!(&*unstyled_str, &*aformat!("<t:{}>", timestamp.unix_timestamp()));
}

#[test]
fn test_message_time_style() {
assert_eq!(FormattedTimestampStyle::ShortTime.to_string(), "t");
assert_eq!(FormattedTimestampStyle::LongTime.to_string(), "T");
assert_eq!(FormattedTimestampStyle::ShortDate.to_string(), "d");
assert_eq!(FormattedTimestampStyle::LongDate.to_string(), "D");
assert_eq!(FormattedTimestampStyle::ShortDateTime.to_string(), "f");
assert_eq!(FormattedTimestampStyle::LongDateTime.to_string(), "F");
assert_eq!(FormattedTimestampStyle::RelativeTime.to_string(), "R");
assert_eq!(&*FormattedTimestampStyle::ShortTime.to_arraystring(), "t");
assert_eq!(&*FormattedTimestampStyle::LongTime.to_arraystring(), "T");
assert_eq!(&*FormattedTimestampStyle::ShortDate.to_arraystring(), "d");
assert_eq!(&*FormattedTimestampStyle::LongDate.to_arraystring(), "D");
assert_eq!(&*FormattedTimestampStyle::ShortDateTime.to_arraystring(), "f");
assert_eq!(&*FormattedTimestampStyle::LongDateTime.to_arraystring(), "F");
assert_eq!(&*FormattedTimestampStyle::RelativeTime.to_arraystring(), "R");
}

#[test]
Expand All @@ -211,7 +237,7 @@ mod tests {

let time = FormattedTimestamp::new(timestamp, Some(FormattedTimestampStyle::ShortDateTime));

let time_str = format!(
let time_str = aformat!(
"<t:{}:{}>",
timestamp.unix_timestamp(),
FormattedTimestampStyle::ShortDateTime
Expand All @@ -223,7 +249,7 @@ mod tests {

let unstyled = FormattedTimestamp::new(timestamp, None);

let unstyled_str = format!("<t:{}>", timestamp.unix_timestamp());
let unstyled_str = aformat!("<t:{}>", timestamp.unix_timestamp());

let unstyled_parsed = unstyled_str.parse::<FormattedTimestamp>().unwrap();

Expand Down
18 changes: 17 additions & 1 deletion src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ pub fn parse_quotes(s: &str) -> Vec<String> {
}

/// Discord's official domains. This is used in [`parse_webhook`] and in its corresponding test.
const DOMAINS: &[&str] = &[
const DOMAINS: [&str; 6] = [
"discord.com",
"canary.discord.com",
"ptb.discord.com",
Expand All @@ -376,6 +376,22 @@ const DOMAINS: &[&str] = &[
"ptb.discordapp.com",
];

const MAX_DOMAIN_LEN: usize = {
let mut max_len = 0;
let mut i = 0;

while i < DOMAINS.len() {
let cur_len = DOMAINS[i].len();
if cur_len > max_len {
max_len = cur_len;
}

i += 1;
}

max_len
};

/// Parses the id and token from a webhook url. Expects a [`url::Url`] rather than a [`&str`].
///
/// # Examples
Expand Down
2 changes: 0 additions & 2 deletions src/utils/quick_modal.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::borrow::Cow;

use to_arraystring::ToArrayString;

use crate::builder::{CreateActionRow, CreateInputText, CreateInteractionResponse, CreateModal};
use crate::client::Context;
use crate::collector::ModalInteractionCollector;
Expand Down

0 comments on commit ed38462

Please sign in to comment.