tentacli 15.2.3

Framework for building extensible network protocol clients via modular plugins.
mod null_terminated;

pub use null_terminated::NullTerminated;

#[macro_export]
macro_rules! enum_field {
    (
        $vis:vis enum $name:ident : $repr:ty {
            $(
                $variant:ident = $value:expr
            ),* $(,)?
        }
    ) => {
        #[repr($repr)]
        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        $vis enum $name {
            $(
                $variant = $value,
            )*
            Unknown($repr),
        }

        impl ::binrw::BinRead for $name {
            type Args<'a> = ();

            fn read_options<R: ::std::io::Read + ::std::io::Seek>(
                reader: &mut R,
                endian: ::binrw::Endian,
                _args: Self::Args<'_>,
            ) -> ::binrw::BinResult<Self> {
                let raw: $repr =
                    <$repr as ::binrw::BinRead>::read_options(reader, endian, ())?;

                Ok(match raw {
                    $(
                        $value => $name::$variant,
                    )*
                    other => $name::Unknown(other),
                })
            }
        }

        impl $crate::client::packet::CalculateMetadata for $name {
            fn calculate<'a>(
                &self,
                ctx: &'a mut $crate::client::packet::MetadataContext,
            ) -> &'a mut $crate::client::packet::MetadataContext {
                let size = ::std::mem::size_of::<$repr>();
                ctx.metadata.insert(
                    ctx.current_key.clone(),
                    $crate::client::packet::MetadataValue {
                        size,
                        offset: ctx.offset,
                    },
                );
                ctx.offset += size;
                ctx
            }
        }

        impl ::serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: ::serde::Serializer,
            {
                fn to_screaming_snake(input: &str) -> String {
                    let mut out = String::with_capacity(input.len() + 8);

                    for (i, ch) in input.chars().enumerate() {
                        if ch.is_uppercase() && i > 0 {
                            out.push('_');
                        }
                        for up in ch.to_uppercase() {
                            out.push(up);
                        }
                    }

                    out
                }

                let name = match self {
                    $(
                        $name::$variant => stringify!($variant),
                    )*
                    $name::Unknown(_) => "UNKNOWN",
                };

                let formatted = to_screaming_snake(name);
                serializer.serialize_str(&formatted)
            }
        }
    };
}