mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 23:44:38 +00:00
use az-registry in az-protocol
This commit is contained in:
parent
4301a2f2d4
commit
fcb5bdf042
19 changed files with 143 additions and 50 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -106,6 +106,7 @@ name = "azalea-block"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azalea-block-macros",
|
"azalea-block-macros",
|
||||||
|
"azalea-buf",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -235,6 +236,7 @@ dependencies = [
|
||||||
"async-compression",
|
"async-compression",
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"azalea-auth",
|
"azalea-auth",
|
||||||
|
"azalea-block",
|
||||||
"azalea-brigadier",
|
"azalea-brigadier",
|
||||||
"azalea-buf",
|
"azalea-buf",
|
||||||
"azalea-chat",
|
"azalea-chat",
|
||||||
|
@ -242,6 +244,7 @@ dependencies = [
|
||||||
"azalea-crypto",
|
"azalea-crypto",
|
||||||
"azalea-nbt",
|
"azalea-nbt",
|
||||||
"azalea-protocol-macros",
|
"azalea-protocol-macros",
|
||||||
|
"azalea-registry",
|
||||||
"azalea-world",
|
"azalea-world",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -268,6 +271,7 @@ dependencies = [
|
||||||
name = "azalea-registry"
|
name = "azalea-registry"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"azalea-buf",
|
||||||
"azalea-registry-macros",
|
"azalea-registry-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -11,3 +11,4 @@ version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
azalea-block-macros = {path = "./azalea-block-macros", version = "^0.1.0"}
|
azalea-block-macros = {path = "./azalea-block-macros", version = "^0.1.0"}
|
||||||
|
azalea-buf = {path = "../azalea-buf", version = "^0.1.0"}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
mod behavior;
|
mod behavior;
|
||||||
mod blocks;
|
mod blocks;
|
||||||
|
|
||||||
|
use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
|
||||||
pub use behavior::BlockBehavior;
|
pub use behavior::BlockBehavior;
|
||||||
pub use blocks::*;
|
pub use blocks::*;
|
||||||
|
use std::{
|
||||||
use std::mem;
|
io::{Read, Write},
|
||||||
|
mem,
|
||||||
|
};
|
||||||
|
|
||||||
impl BlockState {
|
impl BlockState {
|
||||||
/// Transmutes a u32 to a block state.
|
/// Transmutes a u32 to a block state.
|
||||||
|
@ -35,6 +38,20 @@ impl TryFrom<u32> for BlockState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl McBufReadable for BlockState {
|
||||||
|
fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
|
||||||
|
let state_id = u32::var_read_from(buf)?;
|
||||||
|
Self::try_from(state_id).map_err(|_| BufReadError::UnexpectedEnumVariant {
|
||||||
|
id: state_id as i32,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl McBufWritable for BlockState {
|
||||||
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
|
u32::var_write_into(&(*self as u32), buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -74,8 +74,22 @@ fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenSt
|
||||||
variant_discrim += 1;
|
variant_discrim += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let reader = match variant.fields {
|
||||||
|
syn::Fields::Named(_) => {
|
||||||
|
panic!("writing named fields in enums is not supported")
|
||||||
|
}
|
||||||
|
syn::Fields::Unnamed(_) => quote! {
|
||||||
|
Ok(Self::#variant_name(azalea_buf::McBufReadable::read_from(buf)?))
|
||||||
|
},
|
||||||
|
syn::Fields::Unit => quote! {
|
||||||
|
Ok(Self::#variant_name)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
match_contents.extend(quote! {
|
match_contents.extend(quote! {
|
||||||
#variant_discrim => Ok(Self::#variant_name),
|
#variant_discrim => {
|
||||||
|
#reader
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,11 +155,75 @@ fn create_impl_mcbufwritable(ident: &Ident, data: &Data) -> proc_macro2::TokenSt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syn::Data::Enum(syn::DataEnum { .. }) => {
|
syn::Data::Enum(syn::DataEnum { variants, .. }) => {
|
||||||
quote! {
|
// remember whether it's a data variant so we can do an optimization later
|
||||||
impl azalea_buf::McBufWritable for #ident {
|
let mut is_data_enum = false;
|
||||||
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
|
let mut match_arms = quote!();
|
||||||
azalea_buf::McBufVarWritable::var_write_into(&(*self as u32), buf)
|
let mut variant_discrim: u32 = 0;
|
||||||
|
for variant in variants {
|
||||||
|
// figure out the discriminant
|
||||||
|
if let Some(discriminant) = &variant.discriminant {
|
||||||
|
variant_discrim = match &discriminant.1 {
|
||||||
|
syn::Expr::Lit(e) => match &e.lit {
|
||||||
|
syn::Lit::Int(i) => i.base10_parse().unwrap(),
|
||||||
|
_ => panic!("Error parsing enum discriminant as int"),
|
||||||
|
},
|
||||||
|
syn::Expr::Unary(_) => {
|
||||||
|
panic!("Negative enum discriminants are not supported")
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!(
|
||||||
|
"Error parsing enum discriminant as literal (is {:?})",
|
||||||
|
discriminant.1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
variant_discrim += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
match &variant.fields {
|
||||||
|
syn::Fields::Named(_) => {
|
||||||
|
panic!("Enum variants with named fields are not supported yet");
|
||||||
|
}
|
||||||
|
syn::Fields::Unit => {
|
||||||
|
let variant_name = &variant.ident;
|
||||||
|
match_arms.extend(quote! {
|
||||||
|
Self::#variant_name => {
|
||||||
|
azalea_buf::McBufVarWritable::var_write_into(&#variant_discrim, buf)?;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
syn::Fields::Unnamed(_) => {
|
||||||
|
is_data_enum = true;
|
||||||
|
let variant_name = &variant.ident;
|
||||||
|
match_arms.extend(quote! {
|
||||||
|
Self::#variant_name(data) => {
|
||||||
|
azalea_buf::McBufVarWritable::var_write_into(&#variant_discrim, buf)?;
|
||||||
|
azalea_buf::McBufWritable::write_into(data, buf)?;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if is_data_enum {
|
||||||
|
quote! {
|
||||||
|
impl azalea_buf::McBufWritable for #ident {
|
||||||
|
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
|
||||||
|
match self {
|
||||||
|
#match_arms
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// optimization: if it doesn't have data we can just do `as u32`
|
||||||
|
quote! {
|
||||||
|
impl azalea_buf::McBufWritable for #ident {
|
||||||
|
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
|
||||||
|
azalea_buf::McBufVarWritable::var_write_into(&(*self as u32), buf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ version = "0.1.0"
|
||||||
async-compression = {version = "^0.3.8", features = ["tokio", "zlib"], optional = true}
|
async-compression = {version = "^0.3.8", features = ["tokio", "zlib"], optional = true}
|
||||||
async-recursion = "1.0.0"
|
async-recursion = "1.0.0"
|
||||||
azalea-auth = {path = "../azalea-auth", version = "^0.1.0"}
|
azalea-auth = {path = "../azalea-auth", version = "^0.1.0"}
|
||||||
|
azalea-block = {path = "../azalea-block", default-features = false, version = "^0.1.0"}
|
||||||
azalea-brigadier = {path = "../azalea-brigadier", version = "^0.1.0"}
|
azalea-brigadier = {path = "../azalea-brigadier", version = "^0.1.0"}
|
||||||
azalea-buf = {path = "../azalea-buf", version = "^0.1.0"}
|
azalea-buf = {path = "../azalea-buf", version = "^0.1.0"}
|
||||||
azalea-chat = {path = "../azalea-chat", version = "^0.1.1"}
|
azalea-chat = {path = "../azalea-chat", version = "^0.1.1"}
|
||||||
|
@ -18,6 +19,7 @@ azalea-core = {path = "../azalea-core", optional = true, version = "^0.1.0"}
|
||||||
azalea-crypto = {path = "../azalea-crypto", version = "^0.1.0"}
|
azalea-crypto = {path = "../azalea-crypto", version = "^0.1.0"}
|
||||||
azalea-nbt = {path = "../azalea-nbt", version = "^0.1.0"}
|
azalea-nbt = {path = "../azalea-nbt", version = "^0.1.0"}
|
||||||
azalea-protocol-macros = {path = "./azalea-protocol-macros", version = "^0.1.0"}
|
azalea-protocol-macros = {path = "./azalea-protocol-macros", version = "^0.1.0"}
|
||||||
|
azalea-registry = {path = "../azalea-registry", version = "^0.1.0"}
|
||||||
azalea-world = {path = "../azalea-world", version = "^0.1.0"}
|
azalea-world = {path = "../azalea-world", version = "^0.1.0"}
|
||||||
byteorder = "^1.4.3"
|
byteorder = "^1.4.3"
|
||||||
bytes = "^1.1.0"
|
bytes = "^1.1.0"
|
||||||
|
|
|
@ -10,9 +10,7 @@ pub struct ClientboundAddEntityPacket {
|
||||||
#[var]
|
#[var]
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
// TODO: have an entity type enum/struct
|
pub entity_type: azalea_registry::EntityType,
|
||||||
#[var]
|
|
||||||
pub entity_type: i32,
|
|
||||||
pub x: f64,
|
pub x: f64,
|
||||||
pub y: f64,
|
pub y: f64,
|
||||||
pub z: f64,
|
pub z: f64,
|
||||||
|
|
|
@ -9,10 +9,14 @@ pub struct ClientboundAwardStatsPacket {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, McBuf)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, McBuf)]
|
||||||
pub struct Stat {
|
pub enum Stat {
|
||||||
// TODO: make these good enums and stuff
|
Mined(azalea_registry::Block),
|
||||||
#[var]
|
Crafted(azalea_registry::Item),
|
||||||
pub stat_type: u32,
|
Used(azalea_registry::Item),
|
||||||
#[var]
|
Broken(azalea_registry::Item),
|
||||||
pub statistic_id: u32,
|
PickedUp(azalea_registry::Item),
|
||||||
|
Dropped(azalea_registry::Item),
|
||||||
|
Killed(azalea_registry::EntityType),
|
||||||
|
KilledBy(azalea_registry::EntityType),
|
||||||
|
Custom(azalea_registry::CustomStat),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||||
pub struct ClientboundBlockEntityDataPacket {
|
pub struct ClientboundBlockEntityDataPacket {
|
||||||
pub pos: BlockPos,
|
pub pos: BlockPos,
|
||||||
// TODO: in vanilla this uses the block entity registry, we should have an enum in azalea-entity for this
|
pub block_entity_type: azalea_registry::BlockEntityType,
|
||||||
#[var]
|
|
||||||
pub block_entity_type: u32,
|
|
||||||
pub tag: azalea_nbt::Tag,
|
pub tag: azalea_nbt::Tag,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use azalea_block::BlockState;
|
||||||
use azalea_buf::McBuf;
|
use azalea_buf::McBuf;
|
||||||
use azalea_core::BlockPos;
|
use azalea_core::BlockPos;
|
||||||
use azalea_protocol_macros::ClientboundGamePacket;
|
use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
|
@ -7,7 +8,5 @@ pub struct ClientboundBlockEventPacket {
|
||||||
pub pos: BlockPos,
|
pub pos: BlockPos,
|
||||||
pub b0: u8,
|
pub b0: u8,
|
||||||
pub b1: u8,
|
pub b1: u8,
|
||||||
// TODO: this is a BlockState, see ClientboundBlockUpdatePacket for more info
|
pub block: BlockState,
|
||||||
#[var]
|
|
||||||
pub block: u32,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use azalea_block::BlockState;
|
||||||
use azalea_buf::McBuf;
|
use azalea_buf::McBuf;
|
||||||
use azalea_core::BlockPos;
|
use azalea_core::BlockPos;
|
||||||
use azalea_protocol_macros::ClientboundGamePacket;
|
use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
|
@ -5,8 +6,5 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||||
pub struct ClientboundBlockUpdatePacket {
|
pub struct ClientboundBlockUpdatePacket {
|
||||||
pub pos: BlockPos,
|
pub pos: BlockPos,
|
||||||
// TODO: in vanilla this is a BlockState, but here we just have it as a number.
|
pub block_state: BlockState,
|
||||||
// perhaps we could make a crate that only handles block states? right now blockstates are handled in azalea-block
|
|
||||||
#[var]
|
|
||||||
pub block_state: u32,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,7 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
|
|
||||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||||
pub struct ClientboundCooldownPacket {
|
pub struct ClientboundCooldownPacket {
|
||||||
// TODO: make azalea-items or something and use that
|
pub item: azalea_registry::Item,
|
||||||
#[var]
|
|
||||||
pub item: u32,
|
|
||||||
#[var]
|
#[var]
|
||||||
pub duration: u32,
|
pub duration: u32,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,6 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
pub struct ClientboundOpenScreenPacket {
|
pub struct ClientboundOpenScreenPacket {
|
||||||
#[var]
|
#[var]
|
||||||
pub container_id: u32,
|
pub container_id: u32,
|
||||||
// TODO: have an enum of this
|
pub menu_type: azalea_registry::Menu,
|
||||||
#[var]
|
|
||||||
pub menu_type: u32,
|
|
||||||
pub title: Component,
|
pub title: Component,
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,5 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
pub struct ClientboundRemoveMobEffectPacket {
|
pub struct ClientboundRemoveMobEffectPacket {
|
||||||
#[var]
|
#[var]
|
||||||
pub entity_id: u32,
|
pub entity_id: u32,
|
||||||
// TODO: have this use an enum
|
pub effect: azalea_registry::MobEffect,
|
||||||
#[var]
|
|
||||||
pub effect: u32,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,7 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
|
|
||||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||||
pub struct ClientboundSoundEntityPacket {
|
pub struct ClientboundSoundEntityPacket {
|
||||||
// TODO: sound enum/registry
|
pub sound: azalea_registry::SoundEvent,
|
||||||
#[var]
|
|
||||||
pub sound: u32,
|
|
||||||
pub source: SoundSource,
|
pub source: SoundSource,
|
||||||
#[var]
|
#[var]
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
|
|
|
@ -3,9 +3,7 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
|
|
||||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||||
pub struct ClientboundSoundPacket {
|
pub struct ClientboundSoundPacket {
|
||||||
// TODO: sound enum/registry
|
pub sound: azalea_registry::SoundEvent,
|
||||||
#[var]
|
|
||||||
pub sound: u32,
|
|
||||||
pub source: SoundSource,
|
pub source: SoundSource,
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
|
|
|
@ -5,9 +5,7 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
pub struct ClientboundUpdateMobEffectPacket {
|
pub struct ClientboundUpdateMobEffectPacket {
|
||||||
#[var]
|
#[var]
|
||||||
pub entity_id: u32,
|
pub entity_id: u32,
|
||||||
// TODO: have an enum for this
|
pub effect: azalea_registry::MobEffect,
|
||||||
#[var]
|
|
||||||
pub effect: u32,
|
|
||||||
pub effect_amplifier: u8,
|
pub effect_amplifier: u8,
|
||||||
#[var]
|
#[var]
|
||||||
pub effect_duration_ticks: u32,
|
pub effect_duration_ticks: u32,
|
||||||
|
|
|
@ -26,7 +26,6 @@ pub struct ShapelessRecipe {
|
||||||
}
|
}
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ShapedRecipe {
|
pub struct ShapedRecipe {
|
||||||
// TODO: make own McBufReadable and McBufWritable for this
|
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
group: String,
|
group: String,
|
||||||
|
|
|
@ -8,4 +8,5 @@ version = "0.1.0"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
azalea-buf = {path = "../azalea-buf", version = "^0.1.0"}
|
||||||
azalea-registry-macros = {path = "./azalea-registry-macros", version = "^0.1.0"}
|
azalea-registry-macros = {path = "./azalea-registry-macros", version = "^0.1.0"}
|
||||||
|
|
|
@ -67,7 +67,7 @@ pub fn registry(input: TokenStream) -> TokenStream {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
generated.extend(quote! {
|
generated.extend(quote! {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, azalea_buf::McBuf)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
pub enum #name {
|
pub enum #name {
|
||||||
#enum_items
|
#enum_items
|
||||||
|
@ -75,12 +75,16 @@ pub fn registry(input: TokenStream) -> TokenStream {
|
||||||
});
|
});
|
||||||
|
|
||||||
let max_id = input.items.len() as u32;
|
let max_id = input.items.len() as u32;
|
||||||
|
|
||||||
|
let doc_0 = format!("Transmutes a u32 to a {}.", name);
|
||||||
|
let doc_1 = format!("The `id` should be at most {}.", max_id);
|
||||||
|
|
||||||
generated.extend(quote! {
|
generated.extend(quote! {
|
||||||
impl #name {
|
impl #name {
|
||||||
/// Transmutes a u32 to a #name.
|
#[doc = #doc_0]
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// The `id` should be at most #max_id.
|
#[doc = #doc_1]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_u32_unchecked(id: u32) -> Self {
|
pub unsafe fn from_u32_unchecked(id: u32) -> Self {
|
||||||
std::mem::transmute::<u32, #name>(id)
|
std::mem::transmute::<u32, #name>(id)
|
||||||
|
@ -93,11 +97,13 @@ pub fn registry(input: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let doc_0 = format!("Safely transmutes a u32 to a {}.", name);
|
||||||
|
|
||||||
generated.extend(quote! {
|
generated.extend(quote! {
|
||||||
impl TryFrom<u32> for #name {
|
impl TryFrom<u32> for #name {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
/// Safely converts a state id to a block state.
|
#[doc = #doc_0]
|
||||||
fn try_from(id: u32) -> Result<Self, Self::Error> {
|
fn try_from(id: u32) -> Result<Self, Self::Error> {
|
||||||
if Self::is_valid_id(id) {
|
if Self::is_valid_id(id) {
|
||||||
Ok(unsafe { Self::from_u32_unchecked(id) })
|
Ok(unsafe { Self::from_u32_unchecked(id) })
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue