glyde/id
Discord IDs, called snowflakes. Always a String: Discord sends them as JSON strings and nothing ever does arithmetic on one.
Each is tagged with what it identifies, so swapping the two snowflakes in
/channels/{channel_id}/messages/{message_id} will not compile.
Types
pub type Application
pub type ApplicationId =
Id(Application)
pub type Attachment
pub type AttachmentId =
Id(Attachment)
A guild integration, such as a linked Twitch or YouTube account.
pub type Integration
pub type IntegrationId =
Id(Integration)
pub type Interaction
pub type InteractionId =
Id(Interaction)
A permission overwrite, which is addressed by the id of the role or member
it applies to. model/channel.OverwriteTarget says which of the two.
pub type Overwrite
pub type ScheduledEvent
pub type ScheduledEventId =
Id(ScheduledEvent)
A subscription listing, used by role subscriptions.
pub type SubscriptionListing
pub type SubscriptionListingId =
Id(SubscriptionListing)
Names a tag as a value, so retag can be told which one to produce. Empty
and opaque: the constants below are the only ones there are.
pub opaque type Tag(kind)
Values
pub const application: Tag(Application)
pub const attachment: Tag(Attachment)
pub fn compare(a: Id(kind), b: Id(kind)) -> order.Order
Numerically, which for snowflakes is oldest first. Length first because string order is wrong: IDs run 15 to 19 digits with no leading zero.
pub fn created_at_ms(id: Id(kind)) -> Result(Int, Nil)
When this thing was created, in milliseconds since the Unix epoch. Error
when the ID is not a snowflake: not a number at all, or wider than one.
parse rejects both, so only an ID minted with from_string can fail.
pub fn created_at_ms_or(
id: Id(kind),
default default: Int,
) -> Int
created_at_ms for a caller that has to answer with a number either way.
discord_epoch_ms is usually the default to reach for: it reads as the
oldest snowflake there is, so an ID that is not one sorts as ancient
rather than as this instant.
pub fn decoder() -> decode.Decoder(Id(kind))
Strings only: Discord always sends a snowflake as a JSON string, so a number in that slot is a malformed payload.
pub const discord_epoch_ms: Int
Discord’s epoch, 2015-01-01T00:00:00Z, in milliseconds.
pub fn from_string(text: String) -> Id(kind)
An ID minted from a string you trust: a literal, or text you have already
checked. Does not validate, and IDs go straight into request paths, so
parse anything that came from outside.
pub const integration: Tag(Integration)
pub const interaction: Tag(Interaction)
pub fn parse(text: String) -> Result(Id(kind), Nil)
An ID from untrusted input: digits only, no leading zero and no wider than
a snowflake, which is every ID Discord issues. Rejects @me and anything
with a path separator.
pub fn retag(id: Id(a), to tag: Tag(b)) -> Id(b)
The same ID under a different tag, for the places Discord hands one thing
out under two names. Only relabels an ID you already hold: unlike
from_string it cannot bring new text in.
The destination is a tag value rather than inference, so the call site says what it is making and the compiler holds you to it:
id.retag(overwrite.id, to: id.role)
pub const scheduled_event: Tag(ScheduledEvent)
pub const subscription_listing: Tag(SubscriptionListing)