Add deny-unknown-enum-variants features

Add `NONE = -1` variant to Champions
pull/42/head
Mingwei Samuel 2022-06-20 20:43:15 -07:00
parent 2e52b03c63
commit bfa9bdc36e
15 changed files with 89 additions and 43 deletions

View File

@ -28,7 +28,15 @@ default-tls = [ "reqwest/default-tls" ]
native-tls = [ "reqwest/native-tls" ]
rustls-tls = [ "reqwest/rustls-tls" ]
deny-unknown = [ "deny-unknown-fields", "deny-unknown-enum-variants" ]
# If enabled, extra unknown fields encountered during deserialization will
# cause an error instead of being ignored.
deny-unknown-fields = []
# If enabled, deserialization of unknown enum variants will cause an error
# instead of being deserialized to `UNKNOWN` or other integer variants.
deny-unknown-enum-variants = [ "deny-unknown-enum-variants-strings", "deny-unknown-enum-variants-integers" ]
deny-unknown-enum-variants-strings = []
deny-unknown-enum-variants-integers = []
[dependencies]
lazy_static = "1.4"

View File

@ -15,6 +15,7 @@ newtype_enum! {
///
/// Field | Name | Identifier | Id
/// ---|---|---|---
/// `NONE` | None (no ban) | | -1
/// `AATROX` | "Aatrox" | "Aatrox" | 266
/// `AHRI` | "Ahri" | "Ahri" | 103
/// `AKALI` | "Akali" | "Akali" | 84
@ -175,9 +176,10 @@ newtype_enum! {
/// `ZILEAN` | "Zilean" | "Zilean" | 26
/// `ZOE` | "Zoe" | "Zoe" | 142
/// `ZYRA` | "Zyra" | "Zyra" | 143
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub newtype_enum Champion(i16) {
/// `-1`, none. Appears when a champion ban is not used in champ select.
NONE = -1,
/// `266`.
AATROX = 266,
/// `103`.

View File

@ -6,14 +6,14 @@
// //
///////////////////////////////////////////////
use strum_macros::{ EnumString, IntoStaticStr };
use strum_macros::{ EnumString, EnumVariantNames, IntoStaticStr };
/// League of Legends game mode, such as Classic,
/// ARAM, URF, One For All, Ascension, etc.
#[non_exhaustive]
#[derive(Debug, Clone)]
#[derive(Eq, PartialEq, Hash)]
#[derive(EnumString, IntoStaticStr)]
#[derive(EnumString, EnumVariantNames, IntoStaticStr)]
#[repr(u8)]
pub enum GameMode {
/// Catch-all variant for new, unknown game modes.

View File

@ -3,7 +3,7 @@
/// Macro for deriving `Serialize` and `Deserialize` for string enums with an
/// `UNKNOWN(String)` variant.
///
/// Enum should have `#[derive(EnumString, IntoStaticStr)]` included.
/// Enum should have `#[derive(EnumString, EnumVariantNames, IntoStaticStr)]` included.
///
/// Also implements `AsRef<str>`, `Display`, and `From<&str>`.
macro_rules! serde_strum_unknown {
@ -40,7 +40,23 @@ macro_rules! serde_strum_unknown {
where
D: serde::de::Deserializer<'de>
{
<&str>::deserialize(deserializer).map(Into::into)
#[cfg(not(feature = "deny-unknown-enum-variants-strings"))]
{
<&str>::deserialize(deserializer).map(Into::into)
}
#[cfg(feature = "deny-unknown-enum-variants-strings")]
{
<&str>::deserialize(deserializer).map(Into::into)
.and_then(|item| {
match item {
Self::UNKNOWN(unknown) => Err(serde::de::Error::unknown_variant(
&*unknown,
<Self as strum::VariantNames>::VARIANTS,
)),
other => Ok(other),
}
})
}
}
}
}
@ -56,6 +72,13 @@ macro_rules! arr {
}
}
/// Macro for newtype "enums" with integer values.
///
/// For serde, use the following:
/// ```ignore
/// #[derive(Serialize, Deserialize)]
/// #[serde(from = "$repr", into = "$repr")]
/// ```
macro_rules! newtype_enum {
{
$( #[$attr:meta] )*
@ -97,15 +120,49 @@ macro_rules! newtype_enum {
}
}
impl std::convert::From<$name> for $repr {
fn from(value: $name ) -> Self {
value.0
}
}
impl serde::ser::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
<$repr>::serialize(&self.0, serializer)
}
}
impl std::convert::From<$repr> for $name {
fn from(value: $repr ) -> Self {
Self(value)
}
}
impl std::convert::From<$name> for $repr {
fn from(value: $name ) -> Self {
value.0
impl<'de> serde::de::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>
{
#[cfg(not(feature = "deny-unknown-enum-variants-integers"))]
{
<$repr>::deserialize(deserializer).map(Into::into)
}
#[cfg(feature = "deny-unknown-enum-variants-integers")]
{
<$repr>::deserialize(deserializer).map(Into::into)
.and_then(|item: Self| {
if !item.is_known() {
Err(serde::de::Error::custom(format!(
"Unknown integer enum variant: {} (\"deny-unknown-enum-variants-integers\" feature is enabled).\nExpected one of the following: {:?}",
item, Self::ALL_KNOWN
)))
}
else {
Ok(item)
}
})
}
}
}
@ -114,7 +171,6 @@ macro_rules! newtype_enum {
self.0.fmt(f)
}
}
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}({}{})", stringify!($name), self.0, if self.is_known() { "" } else { "?" })

View File

@ -6,12 +6,8 @@
// //
///////////////////////////////////////////////
use serde::{ Serialize, Deserialize };
newtype_enum! {
/// A League of Legends map.
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub newtype_enum Map(u8) {
/// `1`.
/// Summoner's Rift

View File

@ -6,12 +6,8 @@
// //
///////////////////////////////////////////////
use serde::{ Serialize, Deserialize };
newtype_enum! {
/// A League of Legends matchmaking queue.
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub newtype_enum Queue(u16) {
/// `0`.
/// Games on Custom games

View File

@ -1,10 +1,10 @@
use strum_macros::{ EnumString, IntoStaticStr };
use strum_macros::{ EnumString, EnumVariantNames, IntoStaticStr };
/// LoL or TFT ranked queue types.
#[non_exhaustive]
#[derive(Debug, Clone)]
#[derive(Eq, PartialEq, Hash)]
#[derive(EnumString, IntoStaticStr)]
#[derive(EnumString, EnumVariantNames, IntoStaticStr)]
pub enum QueueType {
/// Catch-all variant for new, unknown queue types.
#[strum(default)]
@ -62,6 +62,8 @@ mod test {
}
#[test]
// Note: this test is often not run due to this condition below.
#[cfg(not(feature = "deny-unknown-enum-variants-strings"))]
fn check_deserialize() {
use std::collections::BTreeMap;

View File

@ -6,12 +6,8 @@
// //
///////////////////////////////////////////////
use serde::{ Serialize, Deserialize };
newtype_enum! {
/// A League of Legends season for competitive matchmaking.
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub newtype_enum Season(u8) {
/// `0`.
PRESEASON_3 = 0,

View File

@ -17,6 +17,7 @@ newtype_enum! {
///
/// Field | Name | Identifier | Id
/// ---|---|---|---
/// `NONE` | None (no ban) | | -1
{{
for (const { id, alias, name } of champions) {
}}
@ -24,9 +25,10 @@ newtype_enum! {
{{
}
}}
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub newtype_enum Champion(i16) {
/// `-1`, none. Appears when a champion ban is not used in champ select.
NONE = -1,
{{
for (const { id, alias, name } of champions) {
}}

View File

@ -3,14 +3,14 @@
const gameModes = require('./.gameModes.json');
}}{{= dotUtils.preamble() }}
use strum_macros::{ EnumString, IntoStaticStr };
use strum_macros::{ EnumString, EnumVariantNames, IntoStaticStr };
/// League of Legends game mode, such as Classic,
/// ARAM, URF, One For All, Ascension, etc.
#[non_exhaustive]
#[derive(Debug, Clone)]
#[derive(Eq, PartialEq, Hash)]
#[derive(EnumString, IntoStaticStr)]
#[derive(EnumString, EnumVariantNames, IntoStaticStr)]
#[repr(u8)]
pub enum GameMode {
/// Catch-all variant for new, unknown game modes.

View File

@ -3,12 +3,8 @@
const maps = require('./.maps.json');
}}{{= dotUtils.preamble() }}
use serde::{ Serialize, Deserialize };
newtype_enum! {
/// A League of Legends map.
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub newtype_enum Map(u8) {
{{
for (const e of maps) {

View File

@ -3,12 +3,8 @@
const queues = require('./.queues.json');
}}{{= dotUtils.preamble() }}
use serde::{ Serialize, Deserialize };
newtype_enum! {
/// A League of Legends matchmaking queue.
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub newtype_enum Queue(u16) {
{{
for (const e of queues) {

View File

@ -3,12 +3,8 @@
const seasons = require('./.seasons.json');
}}{{= dotUtils.preamble() }}
use serde::{ Serialize, Deserialize };
newtype_enum! {
/// A League of Legends season for competitive matchmaking.
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub newtype_enum Season(u8) {
{{
for (const e of seasons) {

View File

@ -40,7 +40,7 @@ async_tests! {
// Spot check 10% for `player-data`.
for entry in leaderboard.iter().step_by(10)
{
let player_data = RIOT_API.lol_challenges_v1().get_player_data(ROUTE, &*entry.puuid)
let _player_data = RIOT_API.lol_challenges_v1().get_player_data(ROUTE, &*entry.puuid)
.await.map_err(|e| format!("Failed to get player data PUUID {}: {}", entry.puuid, e))?;
}

View File

@ -9,4 +9,4 @@ cargo +stable test --no-run --features tracing
cargo +nightly test --no-run --features nightly,tracing
# Run tests on nightly.
RGAPI_KEY="$(cat apikey.txt)" RUST_BACKTRACE=1 RUST_LOG=riven=trace cargo +nightly test --features nightly,deny-unknown-fields -- --nocapture
RGAPI_KEY="$(cat apikey.txt)" RUST_BACKTRACE=1 RUST_LOG=riven=trace cargo +nightly test --features nightly,deny-unknown -- --nocapture