1
0
Fork 1
mirror of https://github.com/MingweiSamuel/Riven.git synced 2025-04-17 11:23:15 -07:00

champion.rs build.rs proof of concept

conditional compilation

optional `autoupdate` feature

use feature instead of cfg to avoid recompiling everything

wip

fix include

models/spec wip

generate models.rs

store generated rust in git

update autogen feature deps

grab specs from online

fixes

route

everything except endpoints now

cleanup codegen

preserve schema map order

cleanup meta.rs

final codegen in build.rs

cleanup endpoints codegen

build and docs tidying

document build info

for clippy

cfgs actually working now, oops

cleanup bare urls for rustdoc

newtype enum fix

rephrase docs
This commit is contained in:
Mingwei Samuel 2025-03-07 15:04:44 -08:00
parent aa74790e8b
commit d9ad34a45a
62 changed files with 15264 additions and 12649 deletions

View file

@ -1,3 +1,7 @@
[build]
rustflags = [ "--cfg", "riven_autogen" ]
[env]
RUST_BACKTRACE = "full"
RUST_LOG = "info,riven=debug"
RIVEN_AUTOGEN_DEVMODE = "none"

4
.gitignore vendored
View file

@ -1,5 +1,3 @@
/target
**/*.rs.bk
/doc
apikey.txt
/apikey.txt

48
Cargo.lock generated
View file

@ -505,6 +505,12 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "http"
version = "0.2.12"
@ -743,6 +749,7 @@ checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [
"equivalent",
"hashbrown",
"serde",
]
[[package]]
@ -813,6 +820,22 @@ version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "macro_rules_attribute"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a82271f7bc033d84bbca59a3ce3e4159938cb08a9c3aebbe54d215131518a13"
dependencies = [
"macro_rules_attribute-proc_macro",
"paste",
]
[[package]]
name = "macro_rules_attribute-proc_macro"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8dd856d451cc0da70e2ef2ce95a18e39a93b7558bedf10201ad28503f918568"
[[package]]
name = "memchr"
version = "2.7.4"
@ -1007,6 +1030,12 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "percent-encoding"
version = "2.3.1"
@ -1037,6 +1066,16 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
[[package]]
name = "prettyplease"
version = "0.2.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1ccf34da56fc294e7d4ccf69a85992b7dfb826b7cf57bac6a70bba3494cc08a"
dependencies = [
"proc-macro2",
"syn 2.0.96",
]
[[package]]
name = "proc-macro-crate"
version = "1.3.1"
@ -1174,12 +1213,18 @@ dependencies = [
"fake_instant",
"futures",
"gloo-timers",
"heck 0.5.0",
"hyper",
"indexmap",
"log",
"macro_rules_attribute",
"memo-map",
"metrics",
"num_enum",
"parking_lot",
"prettyplease",
"proc-macro2",
"quote",
"reqwest",
"serde",
"serde_derive",
@ -1188,6 +1233,7 @@ dependencies = [
"slab",
"strum",
"strum_macros",
"syn 2.0.96",
"tokio",
"tokio-shared-rt",
"tracing",
@ -1429,7 +1475,7 @@ version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149"
dependencies = [
"heck",
"heck 0.3.3",
"proc-macro2",
"quote",
"syn 1.0.109",

View file

@ -146,7 +146,6 @@ instance, setting the desired config values, and passing that to [`RiotApi::new`
(instead of just the API key). For example, you can configure the number of
times Riven retries using [`RiotApiConfig::set_retries(...)`](https://docs.rs/riven/latest/riven/struct.RiotApiConfig.html#method.set_retries).
## Semantic Versioning
This package follows semantic versioning to an extent. However, the Riot API
@ -165,6 +164,23 @@ version. (`major.minor.patch`)
Parts of Riven that do not depend on Riot API changes do follow semantic
versioning.
## Auto-Updating
Riven may be configured to automatically update its generated code from the latest version of the
[riotapi-schema](https://github.com/MingweiSamuel/riotapi-schema). This requires an internet
connection, violates semantic versioning, and may break your build. To enable auto-updating, set
the `riven_autogen` cfg option for `rustc` (not a cargo feature).
If the build configuration doesn't change, then the generated code will be cached and not
subsequently update. To change the build configuration and force an update you can set the
`RIVEN_AUTOGEN_NONCE` environment variable to a new value.
For example, setting `RIVEN_AUTOGEN_NONCE` to the current date will trigger an update once a day,
assuming the build configuration otherwise doesn't change:
```bash
RUSTFLAGS="--cfg riven_autogen" RIVEN_AUTOGEN_NONCE="$(date +%Y-%m-%d)" cargo build
```
## Additional Help
Feel free to [make an issue](https://github.com/MingweiSamuel/Riven/issues/new)
@ -172,17 +188,25 @@ if you are have any questions or trouble with Riven.
# Development
NodeJS is used to generate code for Riven. The
[`riven/srcgen`](https://github.com/MingweiSamuel/Riven/tree/v/2.x.x/riven/srcgen)
folder contains the code and [doT.js](https://olado.github.io/doT/index.html)
templates. `index.js` lists the JSON files downloaded and used to generate the
code.
Riven is a regular cargo package for the most part, and can be built directly from the repository
source code without additional consideration. However source files with names matching `*.gen.rs`
have been automatically generated by the `riven/build` build script. The build script is set up to
be skipped by default; to actually update the generated files run `./srcgen.bash`.
To set up the srcgen, you will first need to install NodeJS. Then enter the
`riven/srcgen` folder and run `npm ci` (or `npm install`) to install
dependencies.
## Build Script Configuration
To run the srcgen use `node riven/srcgen` from the repository root.
The the `riven_autogen` cfg option (for `rustc`, not a cargo feature) enables the build script. If
unset, the build script is not even compiled, which ensures fast builds when Riven is used as a
dependency. If set, the build script will be compiled but the actual behavior depends on the
`RIVEN_AUTOGEN_DEVMODE` environment variable. If unset or set to `"outdir"`, will behave as in the
[auto-update](#auto-updating) section above, generating files to `OUT_DIR` to be used by Riven
instead of the checked-in `src` files. If set to `"src"`, the build script will overwrite the files
in `src` directly (this is what `./autogen_src.bash` does). If set to `"none"`, the build script
will be built but will not generate any files. This is the default for the repository, set in
`.cargo/config.toml`, to avoids extraneous updates.
The build script will not generally re-run after the initial build, unless the `RIVEN_AUTOGEN_NONCE`
environment variable changes, or something else in the build configuration changes.
## Testing

4
autogen_src.bash Executable file
View file

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euxo pipefail
RIVEN_AUTOGEN_NONCE="$(date)" RIVEN_AUTOGEN_DEVMODE="src" cargo rustc -p riven

View file

@ -8,9 +8,10 @@ readme = "../README.md"
license = "MIT"
edition = "2018"
rust-version = "1.71.1"
include = [ "/src/**", "/../README.md" ]
include = [ "/src", "/build", "/../README.md" ]
keywords = [ "riot-games", "riot", "league", "league-of-legends" ]
categories = [ "api-bindings", "web-programming::http-client", "wasm" ]
build = "build/main.rs"
[lib]
crate-type = [ "cdylib", "rlib" ]
@ -58,6 +59,7 @@ eserde = { optional = true, version = "0.1.6", features = [ "json" ] }
futures = "0.3.0"
log = "0.4.8"
memo-map = "0.3.0"
macro_rules_attribute = "0.2.0"
metrics = { optional = true, version = "0.24.0" }
num_enum = "0.5.0"
parking_lot = "0.12.0"
@ -95,6 +97,19 @@ console_log = "1.0"
wasm-bindgen = "0.2.70"
wasm-bindgen-test = "0.3"
[target.'cfg(riven_autogen)'.build-dependencies]
heck = "0.5.0"
indexmap = { version = "2.0.0", features = [ "serde" ] }
prettyplease = "0.2.30"
proc-macro2 = "1.0.93"
quote = "1.0.38"
reqwest = { version = "0.11.2", default-features = false, features = [ "gzip" ] }
serde = { version = "1.0.85", features = [ "derive" ] }
serde_derive = "1.0.85"
serde_json = "1.0.1"
syn = "2.0.96"
tokio = { version = "1.20.0", default-features = false, features = [ "rt", "sync" ] }
[target.'cfg(docsrs_deps)'.dependencies]
eserde = { version = "0.1.6", features = [ "json" ] }
gloo-timers = { version = "0.3", features = [ "futures" ] }

View file

@ -0,0 +1,181 @@
use std::collections::BTreeMap;
use heck::ToShoutySnakeCase;
use proc_macro2::{Ident, Literal, Span};
use quote::quote;
use syn::{parse_quote, File};
#[derive(Debug, serde::Deserialize)]
#[allow(dead_code)]
pub struct Champion {
pub id: i16,
pub name: String,
pub alias: String,
pub square_portrait_path: Option<String>,
pub roles: Vec<String>,
}
impl Champion {
fn ident(&self) -> Ident {
Ident::new(&self.alias.to_shouty_snake_case(), Span::call_site())
}
}
pub fn champion(champions: &[Champion]) -> File {
let champions = champions.iter().filter(|&champion| 0 <= champion.id);
let newtype_enum = {
let doc_rows = champions.clone().map(|champion| {
let id = champion.id;
let name = &champion.name;
let alias = &champion.alias;
format!("`{}` | {} | {} | {}", id, name, alias, id)
});
let variants = champions.clone().map(|champion| {
let doc = format!("`{}`", champion.id);
let ident = champion.ident();
let id = Literal::i16_unsuffixed(champion.id);
quote! {
#[doc = #doc]
#ident = #id,
}
});
quote! {
#[macro_rules_attribute::apply(newtype_enum)]
#[repr(i16)]
/// A League of Legends champion.
///
/// This newtype acts as a C-like enum; each variant corresponds to an
/// integer value. Using a newtype allows _unknown_ variants to be
/// represented. This is important when Riot adds new champions.
///
/// Field | Name | Identifier | Id
/// ---|---|---|---
/// `NONE` | None (no ban) | | -1
#( #[doc = #doc_rows ] )*
pub enum Champion {
/// `-1`, none. Appears when a champion ban is not used in champ select.
NONE = -1,
#( #variants )*
}
}
};
let champion_impl = {
let name_cases = champions.clone().map(|champion| {
let ident = champion.ident();
let name = &champion.name;
quote! {
Self::#ident => Some(#name),
}
});
let identifier_doc_rows = champions
.clone()
.filter(|champion| {
champion.alias
!= champion
.name
.replace(|c| char::is_ascii_alphanumeric(&c), "")
})
.map(|champion| {
let id = champion.id;
let name = &champion.name;
let alias = &champion.alias;
format!("`{}` | {} | {} | {}", id, name, alias, id)
});
let identifier_cases = champions.clone().map(|champion| {
let ident = champion.ident();
let alias = &champion.alias;
quote! {
Self::#ident => Some(#alias),
}
});
quote! {
impl Champion {
/// The champion's name (`en_US` localization).
pub const fn name(self) -> Option<&'static str> {
match self {
#( #name_cases )*
_ => None,
}
}
/// The champion's identifier key. Somtimes called "key", "identifier", or "alias".
/// This is mainly used in DDragon paths.
///
/// This is generally the `en_US` name with spaces and punctuation removed,
/// capitalization preserved, however the follow are exceptions:
///
/// Field | Name | Identifier | Id
/// ---|---|---|---
#( #[doc = #identifier_doc_rows] )*
pub const fn identifier(self) -> Option<&'static str> {
match self {
#( #identifier_cases )*
_ => None,
}
}
}
}
};
let champion_parse = {
let cases: BTreeMap<String, &Champion> = champions
.flat_map(|champion| {
IntoIterator::into_iter([&champion.alias, &champion.name]).flat_map(move |s| {
// e.g. `CHOG` for `Cho'Gath`.
let chars_full = s.chars().filter(|c| c.is_ascii_alphanumeric());
// e.g. `CHO` for `Cho'Gath`.
let chars_first = s.chars().take_while(|c| c.is_ascii_alphanumeric());
IntoIterator::into_iter([
Box::new(chars_full) as Box<dyn Iterator<Item = char>>,
Box::new(chars_first),
])
.map(move |chars| {
let str: String = chars
.map(|c| c.to_ascii_uppercase())
.chain(std::iter::repeat('\0'))
.take(4)
.collect();
(str, champion)
})
})
})
.collect();
let cases = cases.into_iter().map(|(s, champion)| {
let ident = champion.ident();
let chars = s.chars().map(Literal::character);
quote! {
[#( #chars ),*] => Ok(Champion::#ident),
}
});
quote! {
impl std::str::FromStr for Champion {
type Err = ParseChampionError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut chars = ['\0'; 4];
s.chars()
.take(4)
.filter(|c| c.is_ascii_alphanumeric())
.map(|c| c.to_ascii_uppercase())
.enumerate()
.for_each(|(i, c)| chars[i] = c);
match chars {
#( #cases )*
unknown => Err(ParseChampionError(unknown)),
}
}
}
}
};
parse_quote! {
#newtype_enum
#champion_impl
#champion_parse
}
}

View file

@ -0,0 +1,393 @@
use std::borrow::Cow;
use heck::{ToPascalCase, ToSnakeCase};
use indexmap::IndexMap;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{parse_quote, File, Ident, PatType};
use super::spec::{
normalize_prop_name, prop_to_type, Operation, Parameter, RequestBody, SchemaEnum, Spec,
};
use super::CODEGEN_NOTE;
pub fn endpoints(spec: &Spec) -> File {
let mut endpoint_groups = IndexMap::<_, Vec<_>>::new();
for (path, path_info) in spec.paths.iter() {
let endpoint = path_info.x_endpoint.as_deref().unwrap();
endpoint_groups
.entry(endpoint)
.or_default()
.push((path, path_info));
}
let impl_riot_api = {
let methods = endpoint_groups.keys().map(|&endpoint| {
let method = Ident::new(&endpoint.to_snake_case(), Span::call_site());
let ty = Ident::new(&endpoint.to_pascal_case(), Span::call_site());
let doc0 = format!(
"Returns a handle for accessing [`{}`](crate::endpoints::{}) endpoints.",
endpoint, ty
);
let doc1 = format!(
"<a href=\"https://developer.riotgames.com/apis#{0}\" target=\"_blank\">`{0}`</a>",
endpoint
);
quote! {
#[doc = #doc0]
///
/// # Riot Developer API Reference
#[doc = #doc1]
///
#[doc = #CODEGEN_NOTE]
#[inline]
pub fn #method(&self) -> #ty<'_> {
#ty { base: self }
}
}
});
quote! {
impl RiotApi {
#( #methods )*
}
}
};
let endpoint_structs = endpoint_groups.keys().map(|endpoint| {
let method = Ident::new(&endpoint.to_snake_case(), Span::call_site());
let ty = Ident::new(&endpoint.to_pascal_case(), Span::call_site());
let doc0 = format!(
"{0} endpoints handle, accessed by calling [`{1}()`](crate::RiotApi::{1}) on a [`RiotApi`] instance.",
endpoint, method,
);
let doc1 = format!("<a href=\"https://developer.riotgames.com/apis#{0}\" target=\"_blank\">`{0}`</a>", endpoint);
quote! {
#[doc = #doc0]
///
/// # Riot Developer API Reference
#[doc = #doc1]
///
#[doc = #CODEGEN_NOTE]
#[repr(transparent)]
pub struct #ty<'a> {
base: &'a RiotApi,
}
}
});
let endpoint_impls = endpoint_groups.iter().map(|(endpoint, methods)| {
let ty = Ident::new(&endpoint.to_pascal_case(), Span::call_site());
let methods = methods
.iter()
.flat_map(|&(path, path_info)| {
path_info
.iter_operations()
.map(move |(verb, op)| (path, verb, op))
})
.map(|(path, verb, op)| {
let op_id = &*op.operation_id;
let method = Ident::new(&op_id.split_once('.').unwrap().1.to_snake_case(), Span::call_site());
let ok_resp = &op.responses.ok;
let is_rso = op
.security
.as_deref()
.is_some_and(|secs| secs.iter().any(|sec| sec.contains_key("rso")));
// Return type checks.
let mut parse_type = None;
let mut return_type = parse_quote!(());
let mut return_optional = false;
if let Some(ok_content) = &ok_resp.content {
let json_info = ok_content
.get("application/json")
.expect("Expected JSON response under `application/json` content type.");
return_type = prop_to_type(&json_info.schema, false, true);
parse_type = Some(return_type.clone());
return_optional = op.x_nullable_404.unwrap_or_default();
if return_optional {
return_type = parse_quote!(Option::<#return_type>);
}
}
// Rustdoc description.
let desc_docs = op
.description
.lines()
.map(str::trim);
let mut method_builder = ArgsBuilder::with_route(op);
if is_rso {
method_builder.add_rso();
}
let all_params = op.parameters.as_deref().unwrap_or_default();
// Path params.
let mut path_params = all_params
.iter()
.filter(|p| "path" == p.r#in)
.collect::<Vec<_>>();
// Important: sort path params by their position in the path.
path_params
.sort_unstable_by_key(|p| path.find(&format!("{{{}}}", p.name)).unwrap());
path_params.iter().for_each(|param| {
method_builder.add_param(param);
});
// Body param.
if let Some(body) = &op.request_body {
method_builder.add_body(body);
}
// Required and optional query params.
let req_query_params = all_params
.iter()
.filter(|p| "query" == p.r#in && p.required);
let opt_query_params = all_params
.iter()
.filter(|p| "query" == p.r#in && !p.required);
req_query_params.into_iter().chain(opt_query_params).for_each(|param| {
method_builder.add_param(param);
});
// Header params.
if all_params.iter().any(|p| "header" == p.r#in) {
panic!("Header params are not implemented: {:?}", all_params);
}
let path_argument = path_argument(path, path_params);
let rso_docs = is_rso.then(|| quote! {
/// # RSO
/// This endpoint uses [Riot Sign On](https://developer.riotgames.com/docs/lol#rso-integration)
/// via the `access_token` parameter, instead of the Riot API key.
///
});
let doc_link = format!("<a href=\"{}\" target=\"_blank\">`{}`</a>", op.external_docs.url, op_id);
let ArgsBuilder { arg_docs, arg_inputs, arg_code } = method_builder;
let verb_ident = Ident::new(&verb.to_ascii_uppercase(), Span::call_site());
let exec_fn = if ok_resp.content.is_some() {
if return_optional {
quote! { execute_opt }
} else {
quote! { execute_val }
}
} else {
quote! { execute }
};
quote! {
#( #[doc = #desc_docs] )*
///
/// # Parameters
#( #[doc = #arg_docs] )*
///
#rso_docs
/// # Riot Developer API Reference
#[doc = #doc_link]
///
#[doc = #CODEGEN_NOTE]
pub fn #method(&self, #( #arg_inputs ),*) -> impl 'a + Future<Output = Result<#return_type>>
{
let route_str = route.into();
let request = self.base.request(Method::#verb_ident, route_str, #path_argument);
#( #arg_code )*
let future = self.base.#exec_fn::<#parse_type>(#op_id, route_str, request);
#[cfg(feature = "tracing")]
let future = future.instrument(tracing::info_span!(#op_id, route = route_str));
#[cfg(feature = "metrics")]
let future = metrics::timed(future, #op_id, route_str);
future
}
}
});
quote! {
#[doc = #CODEGEN_NOTE]
impl<'a> #ty<'a> {
#( #methods )*
}
}
});
parse_quote! {
use std::future::Future;
use std::vec::Vec;
#[cfg(feature="metrics")]
use crate::metrics;
#[cfg(feature="tracing")]
use tracing::Instrument;
use reqwest::Method;
use crate::Result;
use crate::consts::{ RegionalRoute, PlatformRoute, ValPlatformRoute };
use crate::riot_api::RiotApi;
#impl_riot_api
#( #endpoint_structs )*
#( #endpoint_impls )*
}
}
#[derive(Default)]
pub struct ArgsBuilder {
pub arg_docs: Vec<Cow<'static, str>>,
pub arg_inputs: Vec<PatType>,
pub arg_code: Vec<TokenStream>,
}
impl ArgsBuilder {
pub fn with_route(op: &Operation) -> Self {
let mut this = Self::default();
this.arg_inputs.push({
let route_ty = Ident::new(
&format!("{}Route", op.x_route_enum.to_pascal_case()),
Span::call_site(),
);
parse_quote!(route: #route_ty)
});
this.arg_docs.push("- `route` - Route to query.".into());
this
}
pub fn add_rso(&mut self) {
self.arg_docs
.push("- `access_token` - RSO access token.".into());
self.arg_inputs
.push(parse_quote!(access_token: impl std::fmt::Display));
self.arg_code.push(quote! {
let mut request = request.bearer_auth(access_token);
if let Some(clear) = self.base.get_rso_clear_header() {
request = request.header(clear, "")
}
});
}
pub fn add_body(&mut self, body: &RequestBody) {
let name = &parse_quote!(body);
let json_info = body.content.get("application/json").unwrap();
let ty = prop_to_type(&json_info.schema, !body.required, false);
// Docs.
self.push_doc_line("body", body.required, "body", &body.description);
// Args.
self.arg_inputs.push(parse_quote!(#name: &#ty));
// Code.
let body_code = quote! {
request
.body(serde_json::ser::to_vec(#name).unwrap())
.header(reqwest::header::CONTENT_TYPE, "application/json")
};
self.push_code_optional(name, body_code, body.required);
}
pub fn add_param(&mut self, param: &Parameter) {
let required = param.required || "path" == param.r#in;
let key = &*param.name;
let name = &normalize_prop_name(key, None);
let ty = prop_to_type(&param.schema, !required, false);
// Docs.
self.push_doc_line(name, required, &param.r#in, &param.description);
// Args.
self.arg_inputs.push(parse_quote!(#name: #ty));
// Code (path params are handled separately).
if "path" != param.r#in {
let param_code = match &param.schema.schema_enum() {
Some(SchemaEnum::Array { .. }) => quote! {
request.query(&*#name
.iter()
.map(|w| (#key, w))
.collect::<::std::vec::Vec<_>>())
},
Some(SchemaEnum::Object { .. }) => {
panic!("object not expected in query param: `{:?}`.", param.name)
}
Some(_other) => quote! {
request.query(&[(#key, #name)])
},
None => panic!("schema not expected in query param: `{:?}`.", param.name),
};
self.push_code_optional(name, param_code, required);
}
}
fn push_code_optional(&mut self, name: &Ident, mut code: TokenStream, required: bool) {
if !required {
code = quote! {
if let Some(#name) = #name {
#code
} else {
request
}
};
}
self.arg_code.push(quote! {
let request = #code;
});
}
fn push_doc_line(
&mut self,
name: impl std::fmt::Display,
required: bool,
r#in: &str,
description: &Option<String>,
) {
let mut doc_line = format!(
"- `{}` ({}, in {})",
name,
if required { "required" } else { "optional" },
r#in
);
if let Some(description) = description {
doc_line.push_str(" - ");
doc_line.push_str(description);
if !description.ends_with(['.', '!', '?']) {
doc_line.push('.');
}
}
self.arg_docs.push(doc_line.into());
}
}
fn path_argument(path: &String, path_params: Vec<&Parameter>) -> TokenStream {
if path_params.is_empty() {
quote!(#path)
} else {
// Replaces `{someName}` with `{}` for the format string.
let path = path
.chars()
.filter({
let mut active = true;
move |c| match c {
'{' => {
active = false;
true
}
'}' => {
active = true;
true
}
_ => active,
}
})
.collect::<String>();
let path_param_idents = path_params
.iter()
.map(|p| normalize_prop_name(&p.name, None));
quote! {
&format!(
#path,
#( #path_param_idents ),*
)
}
}
}

View file

@ -0,0 +1,63 @@
use proc_macro2::Span;
use quote::quote;
use syn::{parse_quote, File, Ident};
#[derive(Debug, serde::Deserialize)]
pub struct EnumString {
#[serde(rename = "x-name")]
pub x_name: String,
#[serde(rename = "x-desc")]
pub x_desc: String,
#[serde(rename = "x-deprecated")]
pub x_deprecated: Option<bool>,
pub notes: Option<String>,
}
/// Enum with `UNKNOWN(String)` variant for new/unknown values.
pub fn enum_unknown(variants: &[EnumString], ident: Ident, repr: Ident, description: &str) -> File {
let variants = variants.iter().map(
|EnumString {
x_name,
x_desc,
x_deprecated,
notes,
}| {
let docs = x_desc.lines().map(str::trim);
let notes_attr = notes.as_deref().map(|notes| {
quote! {
///
#[doc = #notes]
}
});
let deprecated_attr = x_deprecated.unwrap_or_default().then(|| {
let notes = notes.as_deref().map(|notes| quote!(note = #notes));
quote!(#[deprecated(#notes)])
});
let key = Ident::new(x_name, Span::call_site());
quote! {
#( #[doc = #docs] )*
#notes_attr
#deprecated_attr
#key,
}
},
);
parse_quote! {
use strum_macros::{ EnumString, EnumVariantNames, IntoStaticStr };
#[doc = #description]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(EnumString, EnumVariantNames, IntoStaticStr)]
#[repr(#repr)]
pub enum #ident {
/// Catch-all variant for new/unknown values.
#[strum(default)]
UNKNOWN(String),
#( #variants )*
}
serde_strum_unknown!(#ident);
}
}

View file

@ -0,0 +1,47 @@
use proc_macro2::Span;
use quote::quote;
use syn::{parse_quote, File, Ident};
use super::enum_unknown::EnumString;
pub fn game_type(variants: &[EnumString]) -> File {
let variants = variants.iter().map(
|EnumString {
x_name,
x_desc,
x_deprecated,
notes,
}| {
assert_eq!(
None, *x_deprecated,
"Unexpectedly deprecated `GameType` {}.",
x_name
);
assert_eq!(None, *notes, "Unexpected notes for `GameType` {}.", x_name);
let docs = x_desc.lines().map(str::trim);
let name_no_game = x_name.strip_suffix("_GAME").unwrap_or(x_name);
let key = Ident::new(x_name, Span::call_site());
quote! {
#( #[doc = #docs] )*
// Note: strum(serialize = ...) actually specifies extra **De**serialization values.
#[strum(to_string = #x_name, serialize = #name_no_game)]
#[serde(alias = #name_no_game)]
#key,
}
},
);
parse_quote! {
use strum_macros::{ EnumString, Display, AsRefStr, IntoStaticStr };
/// League of Legends game type: matched game, custom game, or tutorial game.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(EnumString, Display, AsRefStr, IntoStaticStr)]
#[derive(serde::Serialize, crate::de::Deserialize)]
#[repr(u8)]
pub enum GameType {
#( #variants )*
}
}
}

View file

@ -0,0 +1,33 @@
use syn::{parse_quote, File};
use super::spec::Spec;
pub fn meta(spec: &Spec) -> File {
let rows = spec
.paths
.iter()
.flat_map(|(route, path)| {
path.iter_operations()
.map(move |(method, operation)| (&**route, method, operation))
})
.map(|(route, method, operation)| {
let method_ident =
syn::Ident::new(&method.to_ascii_uppercase(), proc_macro2::Span::call_site());
let operation_id = &operation.operation_id;
quote::quote! {
(Method::#method_ident, #route, #operation_id),
}
})
.collect::<Vec<_>>();
let len = rows.len();
parse_quote! {
use reqwest::Method;
/// Metadata for endpoints. Each tuple corresponds to one endpoint and contains
/// the HTTP [`Method`], `str` path, and the method's `str` ID.
pub static ALL_ENDPOINTS: [(Method, &str, &str); #len] = [
#( #rows )*
];
}
}

234
riven/build/autogen/mod.rs Normal file
View file

@ -0,0 +1,234 @@
use std::borrow::Cow;
use std::future::Future;
use std::path::Path;
use syn::parse_quote;
mod champion;
mod endpoints;
mod enum_unknown;
mod game_type;
mod meta;
mod models;
mod newtype_enum;
mod route;
mod spec;
const CODEGEN_NOTE: &str = r#"Note: this item is generated based on <a href="https://github.com/MingweiSamuel/riotapi-schema" target="_blank">`riotapi-schema`</a>."#;
fn spec() -> impl Future<Output = &'static spec::Spec> {
static SPEC: tokio::sync::OnceCell<spec::Spec> = tokio::sync::OnceCell::const_new();
SPEC.get_or_init(|| get("http://www.mingweisamuel.com/riotapi-schema/openapi-3.0.0.json"))
}
pub fn autogen(src_dir: impl AsRef<Path>, consts_dir: impl AsRef<Path>) {
let src_dir = src_dir.as_ref();
let consts_dir = consts_dir.as_ref();
let endpoints_gen = async {
let spec = spec().await;
write(src_dir, "endpoints.gen.rs", endpoints::endpoints(spec)).await;
};
let meta_gen = async {
let spec = spec().await;
write(src_dir, "meta.gen.rs", meta::meta(spec)).await;
};
let models_gen = async {
let spec = spec().await;
write(src_dir, "models.gen.rs", models::models(spec)).await;
};
let champions_gen = async {
let champions = get::<Vec<_>>(
"http://raw.communitydragon.org/pbe/plugins/rcp-be-lol-game-data/global/default/v1/champion-summary.json"
);
write(
consts_dir,
"champion.gen.rs",
champion::champion(&champions.await),
)
.await;
};
let game_mode_gen = async {
let game_modes =
get::<Vec<_>>("http://www.mingweisamuel.com/riotapi-schema/enums/gameModes.json");
write(
consts_dir, "game_mode.gen.rs",
enum_unknown::enum_unknown(
&game_modes.await,
parse_quote!(GameMode),
parse_quote!(u8),
"League of Legends game mode, such as Classic, ARAM, URF, One For All, Ascension, etc.",
),
)
.await;
};
let game_type_gen = async {
let game_types =
get::<Vec<_>>("http://www.mingweisamuel.com/riotapi-schema/enums/gameTypes.json");
write(
consts_dir,
"game_type.gen.rs",
game_type::game_type(&game_types.await),
)
.await;
};
let maps_gen = async {
let maps = get::<Vec<_>>("http://www.mingweisamuel.com/riotapi-schema/enums/maps.json");
write(
consts_dir,
"map.gen.rs",
newtype_enum::newtype_enum(
&maps.await,
parse_quote!(Map),
parse_quote!(u8),
"A League of Legends map.",
),
)
.await;
};
let queue_gen = async {
let queues = get::<Vec<_>>("http://www.mingweisamuel.com/riotapi-schema/enums/queues.json");
write(
consts_dir,
"queue.gen.rs",
newtype_enum::newtype_enum(
&queues.await,
parse_quote!(Queue),
parse_quote!(u16),
"A League of Legends matchmaking queue.",
),
)
.await;
};
let queue_type_gen = async {
let queue_types =
get::<Vec<_>>("http://www.mingweisamuel.com/riotapi-schema/enums/queueTypes.json");
write(
consts_dir,
"queue_type.gen.rs",
enum_unknown::enum_unknown(
&queue_types.await,
parse_quote!(QueueType),
parse_quote!(u8),
"LoL or TFT queue types.",
),
)
.await;
};
let route_gen = async {
let routes_table = get("http://www.mingweisamuel.com/riotapi-schema/routesTable.json");
write(
consts_dir,
"route.gen.rs",
route::route(&routes_table.await),
)
.await;
};
let season_gen = async {
let seasons =
get::<Vec<_>>("http://www.mingweisamuel.com/riotapi-schema/enums/seasons.json");
write(
consts_dir,
"season.gen.rs",
newtype_enum::newtype_enum(
&seasons.await,
parse_quote!(Season),
parse_quote!(u8),
"A League of Legends season for competitive matchmaking.",
),
)
.await
};
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(async move {
tokio::join!(
champions_gen,
endpoints_gen,
meta_gen,
models_gen,
season_gen,
queue_gen,
queue_type_gen,
game_mode_gen,
game_type_gen,
maps_gen,
route_gen,
);
})
}
async fn write(dir: &Path, filename: &str, file: syn::File) {
use std::io::Write;
let path = dir.join(filename);
let mut writer = std::io::BufWriter::new(std::fs::File::create(path).unwrap());
let contents = prettyplease::unparse(&file);
let version = &*spec().await.info.version;
tokio::task::spawn_blocking(move || {
writeln!(
writer,
"// http://www.mingweisamuel.com/riotapi-schema/tool/"
)?;
writeln!(writer, "// Version: {}", version)?;
writeln!(writer)?;
writeln!(writer, "{}", contents)?;
Ok::<(), std::io::Error>(())
})
.await
.unwrap()
.unwrap()
}
fn get<T: serde::de::DeserializeOwned>(url: &str) -> impl use<'_, T> + Future<Output = T> {
static CLIENT: std::sync::OnceLock<reqwest::Client> = std::sync::OnceLock::new();
let client = CLIENT.get_or_init(|| {
reqwest::Client::builder()
.user_agent("riven")
.build()
.unwrap()
});
async move {
let bytes = client
.get(url)
.send()
.await
.unwrap()
.error_for_status()
.unwrap()
.bytes()
.await
.unwrap();
serde_json::from_slice::<T>(&bytes).unwrap()
}
}
fn process_description(description: &str) -> impl Iterator<Item = Cow<'_, str>> {
description.lines().map(str::trim).map(|line| {
let mut line = Cow::Borrowed(line);
let mut i = 0;
while let Some(url_start) = line[i..]
.find("https://")
.or_else(|| line[i..].find("http://"))
.map(|j| i + j)
{
let mut url_end = line[url_start..]
.find(char::is_whitespace)
.map_or(line.len(), |j| url_start + j);
while line.as_bytes().get(url_end - 1) == Some(&b'.') {
url_end -= 1;
}
let mut_line = line.to_mut();
mut_line.insert(url_end, '>');
mut_line.insert(url_start, '<');
i = url_end + 1;
}
line
})
}

View file

@ -0,0 +1,145 @@
use std::borrow::Cow;
use std::collections::HashSet;
use heck::{ToPascalCase, ToSnakeCase};
use indexmap::IndexMap;
use proc_macro2::Span;
use quote::quote;
use syn::{parse_quote, File, Ident};
use super::spec::{
normalize_prop_name, normalize_schema_name, prop_to_type, Schema, SchemaEnum, SchemaOrRef, Spec,
};
use super::{process_description, CODEGEN_NOTE};
pub fn models(spec: &Spec) -> File {
let mut schemas_by_endpoint = IndexMap::<_, Vec<_>>::new();
for (schema_key, schema) in spec.components.schemas.iter() {
if "Error" == *schema_key {
continue;
}
let endpoint = schema_key.split_once('.').unwrap().0;
schemas_by_endpoint
.entry(endpoint)
.or_default()
.push((schema_key, schema));
}
let endpoint_modules = schemas_by_endpoint.into_iter().map(|(endpoint, schemas)| {
let endpoint_ident = Ident::new(&endpoint.to_snake_case(), Span::call_site());
let doc = format!(
"Data structs used by [`{0}`](crate::endpoints::{0})",
endpoint.to_pascal_case()
);
let schemas = schemas
.into_iter()
.map::<syn::ItemStruct, _>(|(schema_key, schema)| {
let schema_name_raw = schema_key.split_once('.').unwrap().1;
let schema_ident = normalize_schema_name(schema_name_raw);
let SchemaOrRef::Schema(Schema {
schema:
SchemaEnum::Object {
title: _,
properties,
required,
additional_properties: _,
x_key: _,
},
description,
x_type: _,
x_alias: _,
}) = &schema
else {
panic!("Schema for `{}` is not an object: {:?}", schema_key, schema);
};
let required = required.iter().flatten().collect::<HashSet<_>>();
// Field docs
let mut docs = vec![Cow::Owned(format!("`{}.{}` data object.", endpoint, schema_name_raw))];
if let Some(description) = description {
docs.push("".into());
docs.push("# Description".into());
docs.extend(process_description(description));
}
// Generate the fields
let mut dedup_names = HashSet::new();
let fields = properties.iter().flatten().map(|(prop_key, prop)| {
let optional = !required.contains(prop_key);
let prop_name = normalize_prop_name(prop_key, Some(&mut dedup_names));
// Docs
let mut docs = prop
.description()
.into_iter()
.flat_map(process_description)
.collect::<Vec<_>>();
// Serde attributes
let mut serde_metas = vec![quote!(rename = #prop_key)];
if let Some(alias) = prop.x_alias() {
serde_metas.push(quote!(alias = #alias));
}
if optional {
serde_metas.push(quote!(default));
serde_metas.push(quote!(skip_serializing_if = "Option::is_none"));
}
let mut deprecated = None;
let mut ty = prop_to_type(prop, optional, true);
// Special handling for specific fields
if "championId" == prop_key && prop.description().is_some_and(|d| d.contains("this field returned invalid championIds")) {
docs.push("".into());
docs.push("Instead use [`Self::champion()`] which checks this field then parses [`Self::champion_name`].".into());
docs.push("<https://github.com/RiotGames/developer-relations/issues/553>".into());
deprecated = Some(quote!(#[deprecated(since = "2.5.0", note = "Use `Participant.champion()` instead. Riot sometimes returns corrupted data for this field: https://github.com/RiotGames/developer-relations/issues/553")]));
serde_metas.push(quote!(serialize_with = "crate::consts::Champion::serialize_result"));
serde_metas.push(quote!(deserialize_with = "crate::consts::Champion::deserialize_result"));
ty = parse_quote!(Result<crate::consts::Champion, std::num::TryFromIntError>);
}
else if "gameType" == prop_key && "InfoDto" == schema_name_raw && "match-v5" == endpoint {
docs.push("".into());
docs.push("Will be `None` if empty string is returned: <https://github.com/RiotGames/developer-relations/issues/898>".into());
serde_metas.push(quote!(serialize_with = "crate::consts::serialize_empty_string_none"));
serde_metas.push(quote!(deserialize_with = "crate::consts::deserialize_empty_string_none"));
ty = parse_quote!(Option<#ty>);
}
quote! {
#( #[doc = #docs] )*
#deprecated
#[serde( #( #serde_metas ),* )]
pub #prop_name: #ty,
}
});
parse_quote! {
#( #[doc = #docs] )*
///
#[doc = #CODEGEN_NOTE]
#[derive(Clone, Debug)]
#[derive(serde::Serialize, crate::de::Deserialize)]
#[cfg_attr(feature = "deny-unknown-fields", serde(deny_unknown_fields))]
pub struct #schema_ident {
#( #fields )*
}
}
});
quote! {
#[doc = #doc]
///
#[doc = #CODEGEN_NOTE]
#[allow(dead_code)]
pub mod #endpoint_ident {
#( #schemas )*
}
}
});
parse_quote! {
#( #endpoint_modules )*
}
}

View file

@ -0,0 +1,65 @@
use proc_macro2::{Literal, Span};
use quote::quote;
use syn::{parse_quote, File, Ident};
#[derive(Debug, serde::Deserialize)]
pub struct EnumInt {
pub notes: Option<String>,
#[serde(rename = "x-value")]
pub x_value: u32,
#[serde(rename = "x-deprecated")]
pub x_deprecated: Option<bool>,
#[serde(rename = "x-desc")]
pub x_desc: Option<String>,
#[serde(rename = "x-name")]
pub x_name: String,
}
pub fn newtype_enum(variants: &[EnumInt], ident: Ident, repr: Ident, description: &str) -> File {
let variants = variants.iter().map(
|EnumInt {
notes,
x_value,
x_deprecated,
x_desc,
x_name,
}| {
let doc = format!("`{}`", x_value);
let mut docs = vec![&*doc];
if let Some(desc) = x_desc {
docs.extend(desc.lines().map(str::trim));
}
if let Some(notes) = notes {
if !docs.contains(&&**notes) {
docs.push("");
docs.push(notes);
}
}
let deprecated_attr = x_deprecated.unwrap_or_default().then(|| {
quote! {
#[deprecated(note = #notes)]
}
});
let ident = Ident::new(x_name, Span::call_site());
let value = Literal::u32_unsuffixed(*x_value);
quote! {
#(
#[doc = #docs]
)*
#deprecated_attr
#ident = #value,
}
},
);
parse_quote! {
#[macro_rules_attribute::apply(newtype_enum)]
#[repr(#repr)]
#[doc = #description]
pub enum #ident {
#(
#variants
)*
}
}
}

View file

@ -0,0 +1,275 @@
use indexmap::IndexMap;
use proc_macro2::{Literal, Span};
use quote::quote;
use syn::{parse_quote, File, Ident, ItemEnum};
#[derive(Debug, serde::Deserialize)]
pub struct RoutesTable {
pub regional: IndexMap<String, Route>,
pub platform: IndexMap<String, Route>,
#[serde(rename = "val-platform")]
pub val_platform: IndexMap<String, Route>,
}
#[derive(Debug, serde::Deserialize)]
pub struct Route {
pub id: u8,
pub description: String,
pub deprecated: Option<bool>,
#[serde(rename = "altName")]
pub alt_name: Option<String>,
#[serde(rename = "tournamentRegion")]
pub tournament_region: Option<String>,
#[serde(rename = "regionalRoute")]
pub regional_route: Option<String>,
#[serde(rename = "regionalRouteLor")]
pub regional_route_lor: Option<String>,
}
pub fn make_enum(routes: &IndexMap<String, Route>, ident: Ident, description: &str) -> ItemEnum {
let variants = routes.iter().map(
|(
route_name,
Route {
id,
description,
deprecated,
alt_name,
..
},
)| {
let route_name = route_name.to_ascii_uppercase();
let docs = description.lines().map(str::trim);
let doc_repr = format!("`{}` (riotapi-schema ID/repr)", id);
let deprecated_attr = deprecated
.unwrap_or_default()
.then(|| quote!(#[deprecated]));
let serialize = alt_name
.as_deref()
.filter(|&alt_name| route_name != alt_name)
// Note: strum(serialize = ...) actually specifies extra **De**serialization values.
.map(|alt_name| quote!(serialize = #alt_name));
let key = Ident::new(&route_name, Span::call_site());
let value = Literal::u8_unsuffixed(*id);
quote! {
#( #[doc = #docs] )*
///
#[doc = #doc_repr]
#deprecated_attr
#[strum(to_string=#route_name, #serialize)]
#key = #value,
}
},
);
parse_quote! {
#[doc = #description]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[repr(u8)]
#[non_exhaustive]
pub enum #ident {
#(
#variants
)*
}
}
}
pub fn route(routes_table: &RoutesTable) -> File {
let regional_route = make_enum(
&routes_table.regional,
parse_quote!(RegionalRoute),
"Regional routes, used in tournament services, Legends of Runeterra (LoR), and some other endpoints.",
);
let platform_route = make_enum(
&routes_table.platform,
parse_quote!(PlatformRoute),
"Platform routes for League of Legends (LoL), Teamfight Tactics (TFT), and Legends of Runeterra (LoR).",
);
let platform_route_impl = {
let route_idents = routes_table
.platform
.keys()
.map(|route_name| Ident::new(&route_name.to_ascii_uppercase(), Span::call_site()))
.collect::<Vec<_>>();
let regional_idents = routes_table.platform.values().map(|route| {
Ident::new(
&route
.regional_route
.as_deref()
.unwrap()
.to_ascii_uppercase(),
Span::call_site(),
)
});
let lor_idents = routes_table.platform.values().map(|route| {
Ident::new(
&route
.regional_route_lor
.as_deref()
.unwrap()
.to_ascii_uppercase(),
Span::call_site(),
)
});
let tournament_regions = routes_table.platform.values().map(|route| {
route
.tournament_region
.as_deref()
.map(|tournament_region| {
let ident = Ident::new(tournament_region, Span::call_site());
quote!(Some(TournamentRegion::#ident))
})
.unwrap_or(quote!(None))
});
let alt_names = routes_table.platform.iter().map(|(route_name, route)| {
route
.alt_name
.as_deref()
.map(|alt_name| quote!(#alt_name))
.unwrap_or_else(|| {
let route_name = route_name.to_ascii_uppercase();
quote!(#route_name)
})
});
quote! {
impl PlatformRoute {
/// Converts this [`PlatformRoute`] into its corresponding
/// [`RegionalRoute`] for LoL and TFT match endpoints such as
/// [`match-v5`](crate::endpoints::MatchV5).
pub fn to_regional(self) -> RegionalRoute {
match self {
#(
Self::#route_idents => RegionalRoute::#regional_idents,
)*
}
}
/// Converts this [`PlatformRoute`] into its corresponding
/// [`RegionalRoute`] for LoR endpoints such as
/// [`lor-match-v1`](crate::endpoints::LorMatchV1).
pub fn to_regional_lor(self) -> RegionalRoute {
match self {
#(
Self::#route_idents => RegionalRoute::#lor_idents,
)*
}
}
/// Used in the LoL Tournament API. Specifically
/// [`tournament-stub-v5.registerProviderData`](crate::endpoints::TournamentStubV5::register_provider_data)
/// and [`tournament-v5.registerProviderData`](crate::endpoints::TournamentV5::register_provider_data).
///
/// Returns `None` if the corresponding tournament region is unknown: <https://github.com/MingweiSamuel/riotapi-schema/issues/58>.
pub fn to_tournament_region(self) -> Option<TournamentRegion> {
match self {
#(
Self::#route_idents => #tournament_regions,
)*
}
}
/// Get the slightly more human-friendly alternate name for this `PlatformRoute`. Specifically
/// excludes any trailing numbers and appends extra N(orth), S(outh), E(ast), and/or W(est)
/// suffixes to some names. Some of these are old region names which are often still used as
/// user-facing names, e.g. on op.gg.
///
/// Note these strings *are* handled by the `FromStr` implementation, if you wish to parse them
/// back into `PlatformRoute`s.
pub fn as_region_str(self) -> &'static str {
match self {
#(
Self::#route_idents => #alt_names,
)*
}
}
}
}
};
let val_platform_route = make_enum(
&routes_table.val_platform,
parse_quote!(ValPlatformRoute),
"Platform routes for Valorant.",
);
let tournament_region = {
let mut variants = routes_table
.platform
.values()
.filter_map(|route| {
route
.tournament_region
.as_deref()
.map(|tournament_region| (tournament_region, route))
})
.collect::<Vec<_>>();
variants.sort_unstable_by_key(|(_, region)| region.id);
let variants = variants.into_iter().map(
|(
tournament_region,
Route {
id,
description,
deprecated,
..
},
)| {
let docs = description.lines().map(str::trim);
let doc_repr = format!("`{}` (riotapi-schema ID/repr)", id);
let deprecated_attr = deprecated
.unwrap_or_default()
.then(|| quote!(#[deprecated]));
let key = Ident::new(tournament_region, Span::call_site());
let value = Literal::u8_unsuffixed(*id);
quote! {
#( #[doc = #docs] )*
///
#[doc = #doc_repr]
#deprecated_attr
#key = #value,
}
},
);
quote! {
/// Tournament regions for League of Legends (LoL) used in
/// [`TournamentStubV5`](crate::endpoints::TournamentStubV5)
/// and [`TournamentV5`](crate::endpoints::TournamentV5).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[derive(serde::Serialize, crate::de::Deserialize)]
#[repr(u8)]
#[non_exhaustive]
pub enum TournamentRegion {
#(
#variants
)*
}
}
};
parse_quote! {
use num_enum::{IntoPrimitive, TryFromPrimitive};
use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};
#regional_route
#platform_route
#platform_route_impl
#val_platform_route
#tournament_region
}
}

318
riven/build/autogen/spec.rs Normal file
View file

@ -0,0 +1,318 @@
#![allow(dead_code)]
use std::collections::HashSet;
use heck::{ToPascalCase, ToSnakeCase};
use indexmap::IndexMap;
use proc_macro2::Span;
use serde_json::Value;
use syn::{parse_quote, Ident, Type};
#[derive(Debug, serde::Deserialize)]
pub struct Spec {
pub openapi: String,
pub info: Info,
// pub servers: Vec<Server>,
pub paths: IndexMap<String, Path>,
pub components: Components,
}
#[derive(Debug, serde::Deserialize)]
pub struct Info {
pub title: String,
pub version: String,
}
#[derive(Debug, serde::Deserialize)]
pub struct Path {
pub get: Option<Operation>,
pub post: Option<Operation>,
pub put: Option<Operation>,
pub delete: Option<Operation>,
pub patch: Option<Operation>,
pub options: Option<Operation>,
pub head: Option<Operation>,
#[serde(rename = "x-endpoint")]
pub x_endpoint: Option<String>,
#[serde(rename = "x-platforms-available")]
pub x_platforms_available: Option<Vec<String>>,
#[serde(rename = "x-route-enum")]
pub x_route_enum: Option<String>,
}
impl Path {
pub fn iter_operations(&self) -> impl Iterator<Item = (&'static str, &Operation)> {
IntoIterator::into_iter([
("get", &self.get),
("post", &self.post),
("put", &self.put),
("delete", &self.delete),
("patch", &self.patch),
("options", &self.options),
("head", &self.head),
])
.filter_map(|(method, op)| op.as_ref().map(|op| (method, op)))
}
}
#[derive(Debug, serde::Deserialize)]
pub struct Operation {
pub tags: Vec<String>,
pub summary: String,
pub description: String,
#[serde(rename = "operationId")]
pub operation_id: String,
pub parameters: Option<Vec<Parameter>>,
#[serde(rename = "externalDocs")]
pub external_docs: ExternalDocs,
#[serde(rename = "requestBody")]
pub request_body: Option<RequestBody>,
pub responses: Responses,
pub security: Option<Vec<IndexMap<String, Vec<String>>>>,
#[serde(rename = "x-route-enum")]
pub x_route_enum: String,
#[serde(rename = "x-nullable-404")]
pub x_nullable_404: Option<bool>,
}
#[derive(Debug, serde::Deserialize)]
pub struct Parameter {
pub name: String,
pub r#in: String,
pub schema: SchemaOrRef,
pub required: bool,
pub description: Option<String>,
}
#[derive(Debug, serde::Deserialize)]
pub struct RequestBody {
pub content: IndexMap<String, MediaType>,
pub required: bool,
pub description: Option<String>,
}
#[derive(Debug, serde::Deserialize)]
pub struct Responses {
#[serde(rename = "200")]
pub ok: Response,
}
#[derive(Debug, serde::Deserialize)]
pub struct Response {
pub description: String,
pub content: Option<IndexMap<String, MediaType>>,
}
#[derive(Debug, serde::Deserialize)]
pub struct MediaType {
pub schema: SchemaOrRef,
pub encoding: Option<IndexMap<String, Value>>,
}
#[derive(Clone, Debug, serde::Deserialize)]
#[serde(untagged)]
pub enum SchemaOrRef {
Schema(Schema),
Ref {
#[serde(rename = "$ref")]
r#ref: String,
#[serde(rename = "x-type")]
x_type: Option<String>,
},
}
impl SchemaOrRef {
pub fn schema_enum(&self) -> Option<&SchemaEnum> {
match self {
SchemaOrRef::Schema(Schema {
schema: schema_enum,
..
}) => Some(schema_enum),
_ => None,
}
}
pub fn description(&self) -> Option<&str> {
match self {
SchemaOrRef::Schema(schema_real) => schema_real.description.as_deref(),
_ => None,
}
}
pub fn x_alias(&self) -> Option<&str> {
match self {
SchemaOrRef::Schema(schema_real) => schema_real.x_alias.as_deref(),
_ => None,
}
}
}
#[derive(Clone, Debug, serde::Deserialize)]
pub struct Schema {
#[serde(flatten)]
pub schema: SchemaEnum,
pub description: Option<String>,
#[serde(rename = "x-type")]
pub x_type: Option<String>,
#[serde(rename = "x-alias")]
pub x_alias: Option<String>,
}
impl Schema {
fn x_enum(&self) -> Option<&str> {
match &self.schema {
SchemaEnum::String { x_enum, .. } => x_enum.as_deref(),
SchemaEnum::Integer { x_enum, .. } => x_enum.as_deref(),
_ => None,
}
}
}
#[derive(Clone, Debug, serde::Deserialize)]
#[serde(tag = "type")]
pub enum SchemaEnum {
#[serde(rename = "array")]
Array {
#[serde(rename = "items")]
items: Box<SchemaOrRef>,
},
#[serde(rename = "object")]
Object {
title: Option<String>,
#[serde(rename = "properties")]
properties: Option<IndexMap<String, SchemaOrRef>>,
#[serde(rename = "required")]
required: Option<Vec<String>>,
#[serde(rename = "additionalProperties")]
additional_properties: Option<Box<SchemaOrRef>>,
#[serde(rename = "x-key")]
x_key: Option<Box<SchemaOrRef>>,
},
#[serde(rename = "string")]
String {
#[serde(rename = "enum")]
r#enum: Option<Vec<String>>,
#[serde(rename = "x-enum")]
x_enum: Option<String>,
},
#[serde(rename = "integer")]
Integer {
format: Option<String>,
#[serde(rename = "x-enum")]
x_enum: Option<String>,
},
#[serde(rename = "number")]
Number { format: String },
#[serde(rename = "boolean")]
Boolean,
}
#[derive(Debug, serde::Deserialize)]
pub struct ExternalDocs {
pub description: String,
pub url: String,
}
#[derive(Debug, serde::Deserialize)]
pub struct Components {
pub schemas: IndexMap<String, SchemaOrRef>,
// #[serde(rename = "securitySchemes")]
// security_schemes: IndexMap<String, SecurityScheme>,
}
pub fn normalize_schema_name(schema_name: &str) -> Ident {
let schema_name = schema_name.replace("DTO", "").replace("Dto", "");
Ident::new(&schema_name, Span::call_site())
}
pub fn normalize_prop_name(prop_name: &str, dedup_names: Option<&mut HashSet<String>>) -> Ident {
let mut prop_name = prop_name.to_snake_case();
if prop_name.starts_with(|c| char::is_ascii_digit(&c)) {
prop_name = format!("x{}", prop_name);
}
if let Some(names) = dedup_names {
while names.contains(&prop_name) {
prop_name.push('_');
}
names.insert(prop_name.clone());
}
if "type" == prop_name {
Ident::new_raw(&prop_name, Span::call_site())
} else {
Ident::new(&prop_name, Span::call_site())
}
}
pub fn prop_to_type(prop: &SchemaOrRef, optional: bool, owned: bool) -> Type {
if optional {
let prop = prop_to_type(prop, false, owned);
return parse_quote!(Option<#prop>);
}
let schema = match prop {
SchemaOrRef::Schema(schema) => schema,
SchemaOrRef::Ref { r#ref, .. } => {
let (endpoint, schema) = r#ref
.strip_prefix("#/components/schemas/")
.unwrap()
.split_once('.')
.unwrap();
let endpoint = Ident::new(&endpoint.to_snake_case(), Span::call_site());
let schema = normalize_schema_name(schema);
return parse_quote!(crate::models::#endpoint::#schema);
}
};
if let Some(x_enum) = schema.x_enum() {
if "locale" != x_enum {
let enum_ident = Ident::new(&x_enum.to_pascal_case(), Span::call_site());
return parse_quote!(crate::consts::#enum_ident);
};
}
match &schema.schema {
SchemaEnum::Array { items } => {
let subtype = prop_to_type(items, false, owned);
if owned {
parse_quote!(Vec<#subtype>)
} else {
parse_quote!(&[#subtype])
}
}
SchemaEnum::Object {
title: _,
properties,
required,
additional_properties,
x_key,
} => {
assert!(
properties.is_none(),
"Schema for is nested object, cannot turn into type name",
);
assert!(required.is_none());
if let (Some(keys), Some(values)) = (x_key, additional_properties) {
let key_type = prop_to_type(keys, false, owned);
let value_type = prop_to_type(values, false, owned);
parse_quote!(::std::collections::HashMap::<#key_type, #value_type>)
} else {
// Only `{ "type": "object" }`.
parse_quote!(crate::serde_json::Map::<String, crate::serde_json::Value>)
}
}
SchemaEnum::String { .. } => {
if owned {
parse_quote!(String)
} else {
parse_quote!(&str)
}
}
SchemaEnum::Integer { format, .. } => match format.as_deref().unwrap() {
"int32" => parse_quote!(i32),
"int64" => parse_quote!(i64),
unknown => panic!("Unknown integer format: {}", unknown),
},
SchemaEnum::Number { format } => match &**format {
"float" => parse_quote!(f32),
"double" => parse_quote!(f64),
unknown => panic!("Unknown number format: {}", unknown),
},
SchemaEnum::Boolean => parse_quote!(bool),
}
}

42
riven/build/main.rs Normal file
View file

@ -0,0 +1,42 @@
// `cargo:rustc-check-cfg` doesn't silence warnings within the build script.
#![allow(unexpected_cfgs)]
#[cfg(riven_autogen)]
pub mod autogen;
pub fn main() {
const RIVEN_AUTOGEN_NONCE: &str = "RIVEN_AUTOGEN_NONCE";
const RIVEN_AUTOGEN_DEVMODE: &str = "RIVEN_AUTOGEN_DEVMODE";
const CFG_RIVEN_AUTOGEN: &str = "riven_autogen";
const CFG_RIVEN_AUTOGEN_OUTDIR: &str = "riven_autogen_outdir";
println!("cargo:rerun-if-changed=build");
println!("cargo:rerun-if-env-changed={}", RIVEN_AUTOGEN_NONCE);
println!("cargo:rerun-if-env-changed={}", RIVEN_AUTOGEN_DEVMODE);
println!("cargo:rustc-check-cfg=cfg({})", CFG_RIVEN_AUTOGEN);
println!("cargo:rustc-check-cfg=cfg({})", CFG_RIVEN_AUTOGEN_OUTDIR);
#[cfg(riven_autogen)]
{
match std::env::var(RIVEN_AUTOGEN_DEVMODE)
.ok()
.map(|s| str::to_ascii_lowercase(&s))
.as_deref()
{
None | Some("outdir") => {
println!("cargo:rustc-cfg={}", CFG_RIVEN_AUTOGEN_OUTDIR);
let out_dir = std::env::var_os("OUT_DIR").unwrap();
autogen::autogen(&*out_dir, &*out_dir);
}
Some("src") => {
autogen::autogen("src", "src/consts");
}
Some("none") => {
// Do nothing.
}
Some(other) => {
panic!("Unknown {}: {:?}", RIVEN_AUTOGEN_DEVMODE, other);
}
}
}
}

View file

@ -130,7 +130,7 @@ fn parse_path<'a>(
// Split URI into region and rest of path.
let req_path = req_path.trim_start_matches('/');
let (route, req_path) = req_path.split_at(req_path.find('/')?);
let route: Route = route.to_uppercase().parse().ok()?;
let route: Route = route.to_ascii_uppercase().parse().ok()?;
// Find method_id for given path.
let method_id = find_matching_method_id(http_method, req_path)?;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,71 @@
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version: 996d171a2b79e9bb85c549f47b07c6ef2721fc8a
use strum_macros::{EnumString, EnumVariantNames, IntoStaticStr};
///League of Legends game mode, such as Classic, ARAM, URF, One For All, Ascension, etc.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(EnumString, EnumVariantNames, IntoStaticStr)]
#[repr(u8)]
pub enum GameMode {
/// Catch-all variant for new/unknown values.
#[strum(default)]
UNKNOWN(String),
///ARAM games
ARAM,
///All Random Summoner's Rift games
ARSR,
///Ascension games
ASCENSION,
///Blood Hunt Assassin games
ASSASSINATE,
///2v2v2v2 Arena
CHERRY,
///Classic Summoner's Rift and Twisted Treeline games
CLASSIC,
///Dark Star: Singularity games
DARKSTAR,
///Doom Bot games
DOOMBOTSTEEMO,
///Snowdown Showdown games
FIRSTBLOOD,
///Nexus Blitz games
GAMEMODEX,
///Legend of the Poro King games
KINGPORO,
///Nexus Blitz games
NEXUSBLITZ,
///Dominion/Crystal Scar games
ODIN,
///Odyssey: Extraction games
ODYSSEY,
///One for All games
ONEFORALL,
///Practice tool training games.
PRACTICETOOL,
///PROJECT: Hunters games
PROJECT,
///Nexus Siege games
SIEGE,
///Star Guardian Invasion games
STARGUARDIAN,
///Swarm
STRAWBERRY,
///Swiftplay Summoner's Rift
SWIFTPLAY,
///Teamfight Tactics.
TFT,
///Tutorial games
TUTORIAL,
///Tutorial: Welcome to League.
TUTORIAL_MODULE_1,
///Tutorial: Power Up.
TUTORIAL_MODULE_2,
///Tutorial: Shop for Gear.
TUTORIAL_MODULE_3,
///Ultimate Spellbook games
ULTBOOK,
///URF games
URF,
}
serde_strum_unknown!(GameMode);

View file

@ -1,82 +0,0 @@
#![cfg_attr(any(), rustfmt::skip)]
///////////////////////////////////////////////
// //
// ! //
// This file is automatically generated! //
// Do not directly edit! //
// //
///////////////////////////////////////////////
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, EnumVariantNames, IntoStaticStr)]
#[repr(u8)]
pub enum GameMode {
/// Catch-all variant for new, unknown game modes.
#[strum(default)]
UNKNOWN(String),
/// ARAM games
ARAM,
/// All Random Summoner's Rift games
ARSR,
/// Ascension games
ASCENSION,
/// Blood Hunt Assassin games
ASSASSINATE,
/// 2v2v2v2 Arena
CHERRY,
/// Classic Summoner's Rift and Twisted Treeline games
CLASSIC,
/// Dark Star: Singularity games
DARKSTAR,
/// Doom Bot games
DOOMBOTSTEEMO,
/// Snowdown Showdown games
FIRSTBLOOD,
/// Nexus Blitz games
GAMEMODEX,
/// Legend of the Poro King games
KINGPORO,
/// Nexus Blitz games
NEXUSBLITZ,
/// Dominion/Crystal Scar games
ODIN,
/// Odyssey: Extraction games
ODYSSEY,
/// One for All games
ONEFORALL,
/// Practice tool training games.
PRACTICETOOL,
/// PROJECT: Hunters games
PROJECT,
/// Nexus Siege games
SIEGE,
/// Star Guardian Invasion games
STARGUARDIAN,
/// Swarm
STRAWBERRY,
/// Swiftplay Summoner's Rift
SWIFTPLAY,
/// Teamfight Tactics.
TFT,
/// Tutorial games
TUTORIAL,
/// Tutorial: Welcome to League.
TUTORIAL_MODULE_1,
/// Tutorial: Power Up.
TUTORIAL_MODULE_2,
/// Tutorial: Shop for Gear.
TUTORIAL_MODULE_3,
/// Ultimate Spellbook games
ULTBOOK,
/// URF games
URF,
}
serde_strum_unknown!(GameMode);

View file

@ -0,0 +1,24 @@
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version: 996d171a2b79e9bb85c549f47b07c6ef2721fc8a
use strum_macros::{EnumString, Display, AsRefStr, IntoStaticStr};
/// League of Legends game type: matched game, custom game, or tutorial game.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(EnumString, Display, AsRefStr, IntoStaticStr)]
#[derive(serde::Serialize, crate::de::Deserialize)]
#[repr(u8)]
pub enum GameType {
///Custom games
#[strum(to_string = "CUSTOM_GAME", serialize = "CUSTOM")]
#[serde(alias = "CUSTOM")]
CUSTOM_GAME,
///all other games
#[strum(to_string = "MATCHED_GAME", serialize = "MATCHED")]
#[serde(alias = "MATCHED")]
MATCHED_GAME,
///Tutorial games
#[strum(to_string = "TUTORIAL_GAME", serialize = "TUTORIAL")]
#[serde(alias = "TUTORIAL")]
TUTORIAL_GAME,
}

View file

@ -1,34 +1,32 @@
#![cfg_attr(any(), rustfmt::skip)]
///////////////////////////////////////////////
// //
// ! //
// This file is automatically generated! //
// Do not directly edit! //
// //
///////////////////////////////////////////////
use strum_macros::{ EnumString, Display, AsRefStr, IntoStaticStr };
/// League of Legends game type: matched game, custom game, or tutorial game.
#[derive(Debug, Copy, Clone)]
#[derive(Eq, PartialEq, Hash)]
#[derive(EnumString, Display, AsRefStr, IntoStaticStr)]
#[derive(serde::Serialize, crate::de::Deserialize)]
#[repr(u8)]
pub enum GameType {
/// Custom games
#[strum(to_string = "CUSTOM_GAME", serialize = "CUSTOM")]
#[serde(alias = "CUSTOM")]
CUSTOM_GAME,
/// all other games
#[strum(to_string = "MATCHED_GAME", serialize = "MATCHED")]
#[serde(alias = "MATCHED")]
MATCHED_GAME,
/// Tutorial games
#[strum(to_string = "TUTORIAL_GAME", serialize = "TUTORIAL")]
#[serde(alias = "TUTORIAL")]
TUTORIAL_GAME,
}
include_autogen!("game_type.gen.rs");
#[cfg(test)]
mod test;
mod test {
use super::*;
#[test]
fn check_as_ref() {
assert_eq!("MATCHED_GAME", GameType::MATCHED_GAME.as_ref());
}
#[test]
fn check_to_string() {
assert_eq!("MATCHED_GAME", GameType::MATCHED_GAME.to_string());
}
#[test]
fn check_from_string() {
assert_eq!(Ok(GameType::MATCHED_GAME), "MATCHED_GAME".parse());
assert_eq!(Ok(GameType::MATCHED_GAME), "MATCHED".parse());
}
#[test]
fn check_serialize() {
assert_eq!(
Some("\"MATCHED_GAME\""),
serde_json::to_string(&GameType::MATCHED_GAME)
.ok()
.as_deref()
);
}
}

View file

@ -1,24 +0,0 @@
use super::*;
#[test]
fn check_as_ref() {
assert_eq!("MATCHED_GAME", GameType::MATCHED_GAME.as_ref());
}
#[test]
fn check_to_string() {
assert_eq!("MATCHED_GAME", GameType::MATCHED_GAME.to_string());
}
#[test]
fn check_from_string() {
assert_eq!(Ok(GameType::MATCHED_GAME), "MATCHED_GAME".parse());
assert_eq!(Ok(GameType::MATCHED_GAME), "MATCHED".parse());
}
#[test]
fn check_serialize() {
assert_eq!(Some("\"MATCHED_GAME\""),
serde_json::to_string(&GameType::MATCHED_GAME)
.ok().as_deref());
}

View file

@ -0,0 +1,80 @@
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version: 996d171a2b79e9bb85c549f47b07c6ef2721fc8a
#[macro_rules_attribute::apply(newtype_enum)]
#[repr(u8)]
///A League of Legends map.
pub enum Map {
///`1`
///Summoner's Rift
///Original Summer variant
#[deprecated(note = "Original Summer variant")]
SUMMONERS_RIFT_ORIGINAL_SUMMER_VARIANT = 1,
///`2`
///Summoner's Rift
///Original Autumn variant
#[deprecated(note = "Original Autumn variant")]
SUMMONERS_RIFT_ORIGINAL_AUTUMN_VARIANT = 2,
///`3`
///The Proving Grounds
///Tutorial Map
THE_PROVING_GROUNDS = 3,
///`4`
///Twisted Treeline
///Original Version
#[deprecated(note = "Original Version")]
TWISTED_TREELINE_ORIGINAL_VERSION = 4,
///`8`
///The Crystal Scar
///Dominion map
THE_CRYSTAL_SCAR = 8,
///`10`
///Twisted Treeline
///Last TT map
TWISTED_TREELINE = 10,
///`11`
///Summoner's Rift
///Current Version
SUMMONERS_RIFT = 11,
///`12`
///Howling Abyss
///ARAM map
HOWLING_ABYSS = 12,
///`14`
///Butcher's Bridge
///Alternate ARAM map
BUTCHERS_BRIDGE = 14,
///`16`
///Cosmic Ruins
///Dark Star: Singularity map
COSMIC_RUINS = 16,
///`18`
///Valoran City Park
///Star Guardian Invasion map
VALORAN_CITY_PARK = 18,
///`19`
///Substructure 43
///PROJECT: Hunters map
SUBSTRUCTURE_43 = 19,
///`20`
///Crash Site
///Odyssey: Extraction map
CRASH_SITE = 20,
///`21`
///Nexus Blitz
///Nexus Blitz map
NEXUS_BLITZ = 21,
///`22`
///Convergence
///Teamfight Tactics map
CONVERGENCE = 22,
///`30`
///Arena
///Map for 2v2v2v2 (`CHERRY`). Team up with a friend or venture solo in this new game mode. Face against multiple teams in chaotic battles across diverse arenas
ARENA = 30,
///`33`
///Swarm
///Map for Swarm (`STRAWBERRY`). Team up with a friend or venture solo in this horde survival mode.
SWARM = 33,
}

View file

@ -1,82 +0,0 @@
#![cfg_attr(any(), rustfmt::skip)]
///////////////////////////////////////////////
// //
// ! //
// This file is automatically generated! //
// Do not directly edit! //
// //
///////////////////////////////////////////////
newtype_enum! {
/// A League of Legends map.
pub newtype_enum Map(u8) {
/// `1`.
/// Summoner's Rift
/// Original Summer variant
SUMMONERS_RIFT_ORIGINAL_SUMMER_VARIANT = 1,
/// `2`.
/// Summoner's Rift
/// Original Autumn variant
SUMMONERS_RIFT_ORIGINAL_AUTUMN_VARIANT = 2,
/// `3`.
/// The Proving Grounds
/// Tutorial Map
THE_PROVING_GROUNDS = 3,
/// `4`.
/// Twisted Treeline
/// Original Version
TWISTED_TREELINE_ORIGINAL_VERSION = 4,
/// `8`.
/// The Crystal Scar
/// Dominion map
THE_CRYSTAL_SCAR = 8,
/// `10`.
/// Twisted Treeline
/// Last TT map
TWISTED_TREELINE = 10,
/// `11`.
/// Summoner's Rift
/// Current Version
SUMMONERS_RIFT = 11,
/// `12`.
/// Howling Abyss
/// ARAM map
HOWLING_ABYSS = 12,
/// `14`.
/// Butcher's Bridge
/// Alternate ARAM map
BUTCHERS_BRIDGE = 14,
/// `16`.
/// Cosmic Ruins
/// Dark Star: Singularity map
COSMIC_RUINS = 16,
/// `18`.
/// Valoran City Park
/// Star Guardian Invasion map
VALORAN_CITY_PARK = 18,
/// `19`.
/// Substructure 43
/// PROJECT: Hunters map
SUBSTRUCTURE_43 = 19,
/// `20`.
/// Crash Site
/// Odyssey: Extraction map
CRASH_SITE = 20,
/// `21`.
/// Nexus Blitz
/// Nexus Blitz map
NEXUS_BLITZ = 21,
/// `22`.
/// Convergence
/// Teamfight Tactics map
CONVERGENCE = 22,
/// `30`.
/// Arena
/// Map for 2v2v2v2 (`CHERRY`). Team up with a friend or venture solo in this new game mode. Face against multiple teams in chaotic battles across diverse arenas
ARENA = 30,
/// `33`.
/// Swarm
/// Map for Swarm (`STRAWBERRY`). Team up with a friend or venture solo in this horde survival mode.
SWARM = 33,
}
}

View file

@ -6,50 +6,46 @@
#![allow(deprecated)]
#![allow(non_camel_case_types)]
mod macros;
/// Trait allowing iteration of enum types, implemented by several enums in this module.
/// Re-exported from strum.
pub use strum::IntoEnumIterator;
#[rustfmt::skip]
mod champion;
pub use champion::*;
mod division;
pub use division::*;
#[rustfmt::skip]
mod game_mode;
mod game_mode {
include_autogen!("game_mode.gen.rs");
}
pub use game_mode::*;
#[rustfmt::skip]
mod game_type;
pub use game_type::*;
#[rustfmt::skip]
mod map;
mod map {
include_autogen!("map.gen.rs");
}
pub use map::*;
#[rustfmt::skip]
mod queue_type;
pub use queue_type::*;
#[rustfmt::skip]
mod queue;
mod queue {
include_autogen!("queue.gen.rs");
}
pub use queue::*;
pub mod ranks;
#[rustfmt::skip]
mod route;
pub use route::*;
mod route_ext;
pub use route_ext::*;
#[rustfmt::skip]
mod season;
mod season {
include_autogen!("season.gen.rs");
}
pub use season::*;
/// Trait allowing iteration of enum types, implemented by several enums in this module.
/// Re-exported from strum.
pub use strum::IntoEnumIterator;
mod team;
pub use team::*;

View file

@ -0,0 +1,432 @@
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version: 996d171a2b79e9bb85c549f47b07c6ef2721fc8a
#[macro_rules_attribute::apply(newtype_enum)]
#[repr(u16)]
///A League of Legends matchmaking queue.
pub enum Queue {
///`0`
///Games on Custom games
CUSTOM = 0,
///`2`
///5v5 Blind Pick games on Summoner's Rift
///
///Deprecated in patch 7.19 in favor of queueId 430
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 430")]
SUMMONERS_RIFT_5V5_BLIND_PICK_DEPRECATED_2 = 2,
///`4`
///5v5 Ranked Solo games on Summoner's Rift
///
///Deprecated in favor of queueId 420
#[deprecated(note = "Deprecated in favor of queueId 420")]
SUMMONERS_RIFT_5V5_RANKED_SOLO_DEPRECATED_4 = 4,
///`6`
///5v5 Ranked Premade games on Summoner's Rift
///
///Game mode deprecated
#[deprecated(note = "Game mode deprecated")]
SUMMONERS_RIFT_5V5_RANKED_PREMADE = 6,
///`7`
///Co-op vs AI games on Summoner's Rift
///
///Deprecated in favor of queueId 32 and 33
#[deprecated(note = "Deprecated in favor of queueId 32 and 33")]
SUMMONERS_RIFT_CO_OP_VS_AI = 7,
///`8`
///3v3 Normal games on Twisted Treeline
///
///Deprecated in patch 7.19 in favor of queueId 460
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 460")]
TWISTED_TREELINE_3V3_NORMAL = 8,
///`9`
///3v3 Ranked Flex games on Twisted Treeline
///
///Deprecated in patch 7.19 in favor of queueId 470
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 470")]
TWISTED_TREELINE_3V3_RANKED_FLEX_DEPRECATED_9 = 9,
///`14`
///5v5 Draft Pick games on Summoner's Rift
///
///Deprecated in favor of queueId 400
#[deprecated(note = "Deprecated in favor of queueId 400")]
SUMMONERS_RIFT_5V5_DRAFT_PICK_DEPRECATED_14 = 14,
///`16`
///5v5 Dominion Blind Pick games on Crystal Scar
///
///Game mode deprecated
#[deprecated(note = "Game mode deprecated")]
CRYSTAL_SCAR_5V5_DOMINION_BLIND_PICK = 16,
///`17`
///5v5 Dominion Draft Pick games on Crystal Scar
///
///Game mode deprecated
#[deprecated(note = "Game mode deprecated")]
CRYSTAL_SCAR_5V5_DOMINION_DRAFT_PICK = 17,
///`25`
///Dominion Co-op vs AI games on Crystal Scar
///
///Game mode deprecated
#[deprecated(note = "Game mode deprecated")]
CRYSTAL_SCAR_DOMINION_CO_OP_VS_AI = 25,
///`31`
///Co-op vs AI Intro Bot games on Summoner's Rift
///
///Deprecated in patch 7.19 in favor of queueId 830
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 830")]
SUMMONERS_RIFT_CO_OP_VS_AI_INTRO_BOT_DEPRECATED_31 = 31,
///`32`
///Co-op vs AI Beginner Bot games on Summoner's Rift
///
///Deprecated in patch 7.19 in favor of queueId 840
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 840")]
SUMMONERS_RIFT_CO_OP_VS_AI_BEGINNER_BOT_DEPRECATED_32 = 32,
///`33`
///Co-op vs AI Intermediate Bot games on Summoner's Rift
///
///Deprecated in patch 7.19 in favor of queueId 850
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 850")]
SUMMONERS_RIFT_CO_OP_VS_AI_INTERMEDIATE_BOT_DEPRECATED_33 = 33,
///`41`
///3v3 Ranked Team games on Twisted Treeline
///
///Game mode deprecated
#[deprecated(note = "Game mode deprecated")]
TWISTED_TREELINE_3V3_RANKED_TEAM = 41,
///`42`
///5v5 Ranked Team games on Summoner's Rift
///
///Game mode deprecated
#[deprecated(note = "Game mode deprecated")]
SUMMONERS_RIFT_5V5_RANKED_TEAM = 42,
///`52`
///Co-op vs AI games on Twisted Treeline
///
///Deprecated in patch 7.19 in favor of queueId 800
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 800")]
TWISTED_TREELINE_CO_OP_VS_AI = 52,
///`61`
///5v5 Team Builder games on Summoner's Rift
///
///Game mode deprecated
#[deprecated(note = "Game mode deprecated")]
SUMMONERS_RIFT_5V5_TEAM_BUILDER = 61,
///`65`
///5v5 ARAM games on Howling Abyss
///
///Deprecated in patch 7.19 in favor of queueId 450
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 450")]
HOWLING_ABYSS_5V5_ARAM_DEPRECATED_65 = 65,
///`67`
///ARAM Co-op vs AI games on Howling Abyss
///
///Game mode deprecated
#[deprecated(note = "Game mode deprecated")]
HOWLING_ABYSS_ARAM_CO_OP_VS_AI = 67,
///`70`
///One for All games on Summoner's Rift
///
///Deprecated in patch 8.6 in favor of queueId 1020
#[deprecated(note = "Deprecated in patch 8.6 in favor of queueId 1020")]
SUMMONERS_RIFT_ONE_FOR_ALL_DEPRECATED_70 = 70,
///`72`
///1v1 Snowdown Showdown games on Howling Abyss
HOWLING_ABYSS_1V1_SNOWDOWN_SHOWDOWN = 72,
///`73`
///2v2 Snowdown Showdown games on Howling Abyss
HOWLING_ABYSS_2V2_SNOWDOWN_SHOWDOWN = 73,
///`75`
///6v6 Hexakill games on Summoner's Rift
SUMMONERS_RIFT_6V6_HEXAKILL = 75,
///`76`
///Ultra Rapid Fire games on Summoner's Rift
SUMMONERS_RIFT_ULTRA_RAPID_FIRE = 76,
///`78`
///One For All: Mirror Mode games on Howling Abyss
HOWLING_ABYSS_ONE_FOR_ALL_MIRROR_MODE = 78,
///`83`
///Co-op vs AI Ultra Rapid Fire games on Summoner's Rift
SUMMONERS_RIFT_CO_OP_VS_AI_ULTRA_RAPID_FIRE = 83,
///`91`
///Doom Bots Rank 1 games on Summoner's Rift
///
///Deprecated in patch 7.19 in favor of queueId 950
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 950")]
SUMMONERS_RIFT_DOOM_BOTS_RANK_1 = 91,
///`92`
///Doom Bots Rank 2 games on Summoner's Rift
///
///Deprecated in patch 7.19 in favor of queueId 950
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 950")]
SUMMONERS_RIFT_DOOM_BOTS_RANK_2 = 92,
///`93`
///Doom Bots Rank 5 games on Summoner's Rift
///
///Deprecated in patch 7.19 in favor of queueId 950
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 950")]
SUMMONERS_RIFT_DOOM_BOTS_RANK_5 = 93,
///`96`
///Ascension games on Crystal Scar
///
///Deprecated in patch 7.19 in favor of queueId 910
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 910")]
CRYSTAL_SCAR_ASCENSION_DEPRECATED_96 = 96,
///`98`
///6v6 Hexakill games on Twisted Treeline
TWISTED_TREELINE_6V6_HEXAKILL = 98,
///`100`
///5v5 ARAM games on Butcher's Bridge
BUTCHERS_BRIDGE_5V5_ARAM = 100,
///`300`
///Legend of the Poro King games on Howling Abyss
///
///Deprecated in patch 7.19 in favor of queueId 920
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 920")]
HOWLING_ABYSS_LEGEND_OF_THE_PORO_KING_DEPRECATED_300 = 300,
///`310`
///Nemesis games on Summoner's Rift
SUMMONERS_RIFT_NEMESIS = 310,
///`313`
///Black Market Brawlers games on Summoner's Rift
SUMMONERS_RIFT_BLACK_MARKET_BRAWLERS = 313,
///`315`
///Nexus Siege games on Summoner's Rift
///
///Deprecated in patch 7.19 in favor of queueId 940
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 940")]
SUMMONERS_RIFT_NEXUS_SIEGE_DEPRECATED_315 = 315,
///`317`
///Definitely Not Dominion games on Crystal Scar
CRYSTAL_SCAR_DEFINITELY_NOT_DOMINION = 317,
///`318`
///ARURF games on Summoner's Rift
///
///Deprecated in patch 7.19 in favor of queueId 900
#[deprecated(note = "Deprecated in patch 7.19 in favor of queueId 900")]
SUMMONERS_RIFT_ARURF_DEPRECATED_318 = 318,
///`325`
///All Random games on Summoner's Rift
SUMMONERS_RIFT_ALL_RANDOM = 325,
///`400`
///5v5 Draft Pick games on Summoner's Rift
SUMMONERS_RIFT_5V5_DRAFT_PICK = 400,
///`410`
///5v5 Ranked Dynamic games on Summoner's Rift
///
///Game mode deprecated in patch 6.22
#[deprecated(note = "Game mode deprecated in patch 6.22")]
SUMMONERS_RIFT_5V5_RANKED_DYNAMIC = 410,
///`420`
///5v5 Ranked Solo games on Summoner's Rift
SUMMONERS_RIFT_5V5_RANKED_SOLO = 420,
///`430`
///5v5 Blind Pick games on Summoner's Rift
SUMMONERS_RIFT_5V5_BLIND_PICK = 430,
///`440`
///5v5 Ranked Flex games on Summoner's Rift
SUMMONERS_RIFT_5V5_RANKED_FLEX = 440,
///`450`
///5v5 ARAM games on Howling Abyss
HOWLING_ABYSS_5V5_ARAM = 450,
///`460`
///3v3 Blind Pick games on Twisted Treeline
///
///Deprecated in patch 9.23
#[deprecated(note = "Deprecated in patch 9.23")]
TWISTED_TREELINE_3V3_BLIND_PICK = 460,
///`470`
///3v3 Ranked Flex games on Twisted Treeline
///
///Deprecated in patch 9.23
#[deprecated(note = "Deprecated in patch 9.23")]
TWISTED_TREELINE_3V3_RANKED_FLEX_DEPRECATED_470 = 470,
///`480`
///Normal (Swiftplay) games on Summoner's Rift
SUMMONERS_RIFT_NORMAL_SWIFTPLAY = 480,
///`490`
///Normal (Quickplay) games on Summoner's Rift
SUMMONERS_RIFT_NORMAL_QUICKPLAY = 490,
///`600`
///Blood Hunt Assassin games on Summoner's Rift
SUMMONERS_RIFT_BLOOD_HUNT_ASSASSIN = 600,
///`610`
///Dark Star: Singularity games on Cosmic Ruins
COSMIC_RUINS_DARK_STAR_SINGULARITY = 610,
///`700`
///Summoner's Rift Clash games on Summoner's Rift
SUMMONERS_RIFT_CLASH = 700,
///`720`
///ARAM Clash games on Howling Abyss
HOWLING_ABYSS_ARAM_CLASH = 720,
///`800`
///Co-op vs. AI Intermediate Bot games on Twisted Treeline
///
///Deprecated in patch 9.23
#[deprecated(note = "Deprecated in patch 9.23")]
TWISTED_TREELINE_CO_OP_VS_AI_INTERMEDIATE_BOT = 800,
///`810`
///Co-op vs. AI Intro Bot games on Twisted Treeline
///
///Deprecated in patch 9.23
#[deprecated(note = "Deprecated in patch 9.23")]
TWISTED_TREELINE_CO_OP_VS_AI_INTRO_BOT = 810,
///`820`
///Co-op vs. AI Beginner Bot games on Twisted Treeline
TWISTED_TREELINE_CO_OP_VS_AI_BEGINNER_BOT = 820,
///`830`
///Co-op vs. AI Intro Bot games on Summoner's Rift
///
///Deprecated in March 2024 in favor of queueId 870
#[deprecated(note = "Deprecated in March 2024 in favor of queueId 870")]
SUMMONERS_RIFT_CO_OP_VS_AI_INTRO_BOT_DEPRECATED_830 = 830,
///`840`
///Co-op vs. AI Beginner Bot games on Summoner's Rift
///
///Deprecated in March 2024 in favor of queueId 880
#[deprecated(note = "Deprecated in March 2024 in favor of queueId 880")]
SUMMONERS_RIFT_CO_OP_VS_AI_BEGINNER_BOT_DEPRECATED_840 = 840,
///`850`
///Co-op vs. AI Intermediate Bot games on Summoner's Rift
///
///Deprecated in March 2024 in favor of queueId 890
#[deprecated(note = "Deprecated in March 2024 in favor of queueId 890")]
SUMMONERS_RIFT_CO_OP_VS_AI_INTERMEDIATE_BOT_DEPRECATED_850 = 850,
///`870`
///Co-op vs. AI Intro Bot games on Summoner's Rift
SUMMONERS_RIFT_CO_OP_VS_AI_INTRO_BOT = 870,
///`880`
///Co-op vs. AI Beginner Bot games on Summoner's Rift
SUMMONERS_RIFT_CO_OP_VS_AI_BEGINNER_BOT = 880,
///`890`
///Co-op vs. AI Intermediate Bot games on Summoner's Rift
SUMMONERS_RIFT_CO_OP_VS_AI_INTERMEDIATE_BOT = 890,
///`900`
///ARURF games on Summoner's Rift
SUMMONERS_RIFT_ARURF = 900,
///`910`
///Ascension games on Crystal Scar
CRYSTAL_SCAR_ASCENSION = 910,
///`920`
///Legend of the Poro King games on Howling Abyss
HOWLING_ABYSS_LEGEND_OF_THE_PORO_KING = 920,
///`940`
///Nexus Siege games on Summoner's Rift
SUMMONERS_RIFT_NEXUS_SIEGE = 940,
///`950`
///Doom Bots Voting games on Summoner's Rift
SUMMONERS_RIFT_DOOM_BOTS_VOTING = 950,
///`960`
///Doom Bots Standard games on Summoner's Rift
SUMMONERS_RIFT_DOOM_BOTS_STANDARD = 960,
///`980`
///Star Guardian Invasion: Normal games on Valoran City Park
VALORAN_CITY_PARK_STAR_GUARDIAN_INVASION_NORMAL = 980,
///`990`
///Star Guardian Invasion: Onslaught games on Valoran City Park
VALORAN_CITY_PARK_STAR_GUARDIAN_INVASION_ONSLAUGHT = 990,
///`1000`
///PROJECT: Hunters games on Overcharge
OVERCHARGE_PROJECT_HUNTERS = 1000,
///`1010`
///Snow ARURF games on Summoner's Rift
SUMMONERS_RIFT_SNOW_ARURF = 1010,
///`1020`
///One for All games on Summoner's Rift
SUMMONERS_RIFT_ONE_FOR_ALL = 1020,
///`1030`
///Odyssey Extraction: Intro games on Crash Site
CRASH_SITE_ODYSSEY_EXTRACTION_INTRO = 1030,
///`1040`
///Odyssey Extraction: Cadet games on Crash Site
CRASH_SITE_ODYSSEY_EXTRACTION_CADET = 1040,
///`1050`
///Odyssey Extraction: Crewmember games on Crash Site
CRASH_SITE_ODYSSEY_EXTRACTION_CREWMEMBER = 1050,
///`1060`
///Odyssey Extraction: Captain games on Crash Site
CRASH_SITE_ODYSSEY_EXTRACTION_CAPTAIN = 1060,
///`1070`
///Odyssey Extraction: Onslaught games on Crash Site
CRASH_SITE_ODYSSEY_EXTRACTION_ONSLAUGHT = 1070,
///`1090`
///Teamfight Tactics games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS = 1090,
///`1091`
///Teamfight Tactics 1v0 games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_1V0 = 1091,
///`1092`
///Teamfight Tactics 2v0 games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_2V0 = 1092,
///`1100`
///Ranked Teamfight Tactics games on Convergence
CONVERGENCE_RANKED_TEAMFIGHT_TACTICS = 1100,
///`1110`
///Teamfight Tactics Tutorial games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_TUTORIAL = 1110,
///`1111`
///Teamfight Tactics Simluation games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_SIMLUATION = 1111,
///`1130`
///Ranked Teamfight Tactics (Hyper Roll) games on Convergence
CONVERGENCE_RANKED_TEAMFIGHT_TACTICS_HYPER_ROLL = 1130,
///`1150`
///Ranked Teamfight Tactics (Double Up Workshop) games on Convergence
///
///Deprecated in patch 12.11 in favor of queueId 1160
#[deprecated(note = "Deprecated in patch 12.11 in favor of queueId 1160")]
CONVERGENCE_RANKED_TEAMFIGHT_TACTICS_DOUBLE_UP_WORKSHOP_DEPRECATED_1150 = 1150,
///`1160`
///Ranked Teamfight Tactics (Double Up Workshop) games on Convergence
CONVERGENCE_RANKED_TEAMFIGHT_TACTICS_DOUBLE_UP_WORKSHOP = 1160,
///`1200`
///Nexus Blitz games on Nexus Blitz
///
///Deprecated in patch 9.2 in favor of queueId 1300
#[deprecated(note = "Deprecated in patch 9.2 in favor of queueId 1300")]
NEXUS_BLITZ_DEPRECATED_1200 = 1200,
///`1210`
///Teamfight Tactics (Choncc's Treasure) games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_CHONCCS_TREASURE = 1210,
///`1300`
///Nexus Blitz games on Nexus Blitz
NEXUS_BLITZ = 1300,
///`1400`
///Ultimate Spellbook games on Summoner's Rift
SUMMONERS_RIFT_ULTIMATE_SPELLBOOK = 1400,
///`1700`
///2v2v2v2 `CHERRY` games on Arena
ARENA_2V2V2V2_CHERRY = 1700,
///`1710`
///Arena (`CHERRY` games) games on Rings of Wrath
RINGS_OF_WRATH_ARENA_CHERRY_GAMES = 1710,
///`1810`
///Swarm solo (`STRAWBERRY` games) games on Swarm
SWARM_SOLO_STRAWBERRY_GAMES = 1810,
///`1820`
///Swarm duo (`STRAWBERRY` games) games on Swarm
SWARM_DUO_STRAWBERRY_GAMES = 1820,
///`1830`
///Swarm trio (`STRAWBERRY` games) games on Swarm
SWARM_TRIO_STRAWBERRY_GAMES = 1830,
///`1840`
///Swarm quad (`STRAWBERRY` games) games on Swarm
SWARM_QUAD_STRAWBERRY_GAMES = 1840,
///`1900`
///Pick URF games on Summoner's Rift
SUMMONERS_RIFT_PICK_URF = 1900,
///`2000`
///Tutorial 1 games on Summoner's Rift
SUMMONERS_RIFT_TUTORIAL_1 = 2000,
///`2010`
///Tutorial 2 games on Summoner's Rift
SUMMONERS_RIFT_TUTORIAL_2 = 2010,
///`2020`
///Tutorial 3 games on Summoner's Rift
SUMMONERS_RIFT_TUTORIAL_3 = 2020,
///`6000`
///Teamfight Tactics Set 3.5 Revival games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_SET_3_5_REVIVAL = 6000,
///`6100`
///Teamfight Tactics Revival: Festival of Beasts games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_REVIVAL_FESTIVAL_OF_BEASTS = 6100,
}

View file

@ -1,437 +0,0 @@
#![cfg_attr(any(), rustfmt::skip)]
///////////////////////////////////////////////
// //
// ! //
// This file is automatically generated! //
// Do not directly edit! //
// //
///////////////////////////////////////////////
newtype_enum! {
/// A League of Legends matchmaking queue.
pub newtype_enum Queue(u16) {
/// `0`.
/// Games on Custom games
CUSTOM = 0,
/// `2`.
/// 5v5 Blind Pick games on Summoner's Rift
///
/// Deprecated in patch 7.19 in favor of queueId 430
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 430")]
SUMMONERS_RIFT_5V5_BLIND_PICK_DEPRECATED_2 = 2,
/// `4`.
/// 5v5 Ranked Solo games on Summoner's Rift
///
/// Deprecated in favor of queueId 420
#[deprecated(note="Deprecated in favor of queueId 420")]
SUMMONERS_RIFT_5V5_RANKED_SOLO_DEPRECATED_4 = 4,
/// `6`.
/// 5v5 Ranked Premade games on Summoner's Rift
///
/// Game mode deprecated
#[deprecated(note="Game mode deprecated")]
SUMMONERS_RIFT_5V5_RANKED_PREMADE = 6,
/// `7`.
/// Co-op vs AI games on Summoner's Rift
///
/// Deprecated in favor of queueId 32 and 33
#[deprecated(note="Deprecated in favor of queueId 32 and 33")]
SUMMONERS_RIFT_CO_OP_VS_AI = 7,
/// `8`.
/// 3v3 Normal games on Twisted Treeline
///
/// Deprecated in patch 7.19 in favor of queueId 460
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 460")]
TWISTED_TREELINE_3V3_NORMAL = 8,
/// `9`.
/// 3v3 Ranked Flex games on Twisted Treeline
///
/// Deprecated in patch 7.19 in favor of queueId 470
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 470")]
TWISTED_TREELINE_3V3_RANKED_FLEX_DEPRECATED_9 = 9,
/// `14`.
/// 5v5 Draft Pick games on Summoner's Rift
///
/// Deprecated in favor of queueId 400
#[deprecated(note="Deprecated in favor of queueId 400")]
SUMMONERS_RIFT_5V5_DRAFT_PICK_DEPRECATED_14 = 14,
/// `16`.
/// 5v5 Dominion Blind Pick games on Crystal Scar
///
/// Game mode deprecated
#[deprecated(note="Game mode deprecated")]
CRYSTAL_SCAR_5V5_DOMINION_BLIND_PICK = 16,
/// `17`.
/// 5v5 Dominion Draft Pick games on Crystal Scar
///
/// Game mode deprecated
#[deprecated(note="Game mode deprecated")]
CRYSTAL_SCAR_5V5_DOMINION_DRAFT_PICK = 17,
/// `25`.
/// Dominion Co-op vs AI games on Crystal Scar
///
/// Game mode deprecated
#[deprecated(note="Game mode deprecated")]
CRYSTAL_SCAR_DOMINION_CO_OP_VS_AI = 25,
/// `31`.
/// Co-op vs AI Intro Bot games on Summoner's Rift
///
/// Deprecated in patch 7.19 in favor of queueId 830
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 830")]
SUMMONERS_RIFT_CO_OP_VS_AI_INTRO_BOT_DEPRECATED_31 = 31,
/// `32`.
/// Co-op vs AI Beginner Bot games on Summoner's Rift
///
/// Deprecated in patch 7.19 in favor of queueId 840
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 840")]
SUMMONERS_RIFT_CO_OP_VS_AI_BEGINNER_BOT_DEPRECATED_32 = 32,
/// `33`.
/// Co-op vs AI Intermediate Bot games on Summoner's Rift
///
/// Deprecated in patch 7.19 in favor of queueId 850
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 850")]
SUMMONERS_RIFT_CO_OP_VS_AI_INTERMEDIATE_BOT_DEPRECATED_33 = 33,
/// `41`.
/// 3v3 Ranked Team games on Twisted Treeline
///
/// Game mode deprecated
#[deprecated(note="Game mode deprecated")]
TWISTED_TREELINE_3V3_RANKED_TEAM = 41,
/// `42`.
/// 5v5 Ranked Team games on Summoner's Rift
///
/// Game mode deprecated
#[deprecated(note="Game mode deprecated")]
SUMMONERS_RIFT_5V5_RANKED_TEAM = 42,
/// `52`.
/// Co-op vs AI games on Twisted Treeline
///
/// Deprecated in patch 7.19 in favor of queueId 800
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 800")]
TWISTED_TREELINE_CO_OP_VS_AI = 52,
/// `61`.
/// 5v5 Team Builder games on Summoner's Rift
///
/// Game mode deprecated
#[deprecated(note="Game mode deprecated")]
SUMMONERS_RIFT_5V5_TEAM_BUILDER = 61,
/// `65`.
/// 5v5 ARAM games on Howling Abyss
///
/// Deprecated in patch 7.19 in favor of queueId 450
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 450")]
HOWLING_ABYSS_5V5_ARAM_DEPRECATED_65 = 65,
/// `67`.
/// ARAM Co-op vs AI games on Howling Abyss
///
/// Game mode deprecated
#[deprecated(note="Game mode deprecated")]
HOWLING_ABYSS_ARAM_CO_OP_VS_AI = 67,
/// `70`.
/// One for All games on Summoner's Rift
///
/// Deprecated in patch 8.6 in favor of queueId 1020
#[deprecated(note="Deprecated in patch 8.6 in favor of queueId 1020")]
SUMMONERS_RIFT_ONE_FOR_ALL_DEPRECATED_70 = 70,
/// `72`.
/// 1v1 Snowdown Showdown games on Howling Abyss
HOWLING_ABYSS_1V1_SNOWDOWN_SHOWDOWN = 72,
/// `73`.
/// 2v2 Snowdown Showdown games on Howling Abyss
HOWLING_ABYSS_2V2_SNOWDOWN_SHOWDOWN = 73,
/// `75`.
/// 6v6 Hexakill games on Summoner's Rift
SUMMONERS_RIFT_6V6_HEXAKILL = 75,
/// `76`.
/// Ultra Rapid Fire games on Summoner's Rift
SUMMONERS_RIFT_ULTRA_RAPID_FIRE = 76,
/// `78`.
/// One For All: Mirror Mode games on Howling Abyss
HOWLING_ABYSS_ONE_FOR_ALL_MIRROR_MODE = 78,
/// `83`.
/// Co-op vs AI Ultra Rapid Fire games on Summoner's Rift
SUMMONERS_RIFT_CO_OP_VS_AI_ULTRA_RAPID_FIRE = 83,
/// `91`.
/// Doom Bots Rank 1 games on Summoner's Rift
///
/// Deprecated in patch 7.19 in favor of queueId 950
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 950")]
SUMMONERS_RIFT_DOOM_BOTS_RANK_1 = 91,
/// `92`.
/// Doom Bots Rank 2 games on Summoner's Rift
///
/// Deprecated in patch 7.19 in favor of queueId 950
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 950")]
SUMMONERS_RIFT_DOOM_BOTS_RANK_2 = 92,
/// `93`.
/// Doom Bots Rank 5 games on Summoner's Rift
///
/// Deprecated in patch 7.19 in favor of queueId 950
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 950")]
SUMMONERS_RIFT_DOOM_BOTS_RANK_5 = 93,
/// `96`.
/// Ascension games on Crystal Scar
///
/// Deprecated in patch 7.19 in favor of queueId 910
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 910")]
CRYSTAL_SCAR_ASCENSION_DEPRECATED_96 = 96,
/// `98`.
/// 6v6 Hexakill games on Twisted Treeline
TWISTED_TREELINE_6V6_HEXAKILL = 98,
/// `100`.
/// 5v5 ARAM games on Butcher's Bridge
BUTCHERS_BRIDGE_5V5_ARAM = 100,
/// `300`.
/// Legend of the Poro King games on Howling Abyss
///
/// Deprecated in patch 7.19 in favor of queueId 920
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 920")]
HOWLING_ABYSS_LEGEND_OF_THE_PORO_KING_DEPRECATED_300 = 300,
/// `310`.
/// Nemesis games on Summoner's Rift
SUMMONERS_RIFT_NEMESIS = 310,
/// `313`.
/// Black Market Brawlers games on Summoner's Rift
SUMMONERS_RIFT_BLACK_MARKET_BRAWLERS = 313,
/// `315`.
/// Nexus Siege games on Summoner's Rift
///
/// Deprecated in patch 7.19 in favor of queueId 940
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 940")]
SUMMONERS_RIFT_NEXUS_SIEGE_DEPRECATED_315 = 315,
/// `317`.
/// Definitely Not Dominion games on Crystal Scar
CRYSTAL_SCAR_DEFINITELY_NOT_DOMINION = 317,
/// `318`.
/// ARURF games on Summoner's Rift
///
/// Deprecated in patch 7.19 in favor of queueId 900
#[deprecated(note="Deprecated in patch 7.19 in favor of queueId 900")]
SUMMONERS_RIFT_ARURF_DEPRECATED_318 = 318,
/// `325`.
/// All Random games on Summoner's Rift
SUMMONERS_RIFT_ALL_RANDOM = 325,
/// `400`.
/// 5v5 Draft Pick games on Summoner's Rift
SUMMONERS_RIFT_5V5_DRAFT_PICK = 400,
/// `410`.
/// 5v5 Ranked Dynamic games on Summoner's Rift
///
/// Game mode deprecated in patch 6.22
#[deprecated(note="Game mode deprecated in patch 6.22")]
SUMMONERS_RIFT_5V5_RANKED_DYNAMIC = 410,
/// `420`.
/// 5v5 Ranked Solo games on Summoner's Rift
SUMMONERS_RIFT_5V5_RANKED_SOLO = 420,
/// `430`.
/// 5v5 Blind Pick games on Summoner's Rift
SUMMONERS_RIFT_5V5_BLIND_PICK = 430,
/// `440`.
/// 5v5 Ranked Flex games on Summoner's Rift
SUMMONERS_RIFT_5V5_RANKED_FLEX = 440,
/// `450`.
/// 5v5 ARAM games on Howling Abyss
HOWLING_ABYSS_5V5_ARAM = 450,
/// `460`.
/// 3v3 Blind Pick games on Twisted Treeline
///
/// Deprecated in patch 9.23
#[deprecated(note="Deprecated in patch 9.23")]
TWISTED_TREELINE_3V3_BLIND_PICK = 460,
/// `470`.
/// 3v3 Ranked Flex games on Twisted Treeline
///
/// Deprecated in patch 9.23
#[deprecated(note="Deprecated in patch 9.23")]
TWISTED_TREELINE_3V3_RANKED_FLEX_DEPRECATED_470 = 470,
/// `480`.
/// Normal (Swiftplay) games on Summoner's Rift
SUMMONERS_RIFT_NORMAL_SWIFTPLAY = 480,
/// `490`.
/// Normal (Quickplay) games on Summoner's Rift
SUMMONERS_RIFT_NORMAL_QUICKPLAY = 490,
/// `600`.
/// Blood Hunt Assassin games on Summoner's Rift
SUMMONERS_RIFT_BLOOD_HUNT_ASSASSIN = 600,
/// `610`.
/// Dark Star: Singularity games on Cosmic Ruins
COSMIC_RUINS_DARK_STAR_SINGULARITY = 610,
/// `700`.
/// Summoner's Rift Clash games on Summoner's Rift
SUMMONERS_RIFT_CLASH = 700,
/// `720`.
/// ARAM Clash games on Howling Abyss
HOWLING_ABYSS_ARAM_CLASH = 720,
/// `800`.
/// Co-op vs. AI Intermediate Bot games on Twisted Treeline
///
/// Deprecated in patch 9.23
#[deprecated(note="Deprecated in patch 9.23")]
TWISTED_TREELINE_CO_OP_VS_AI_INTERMEDIATE_BOT = 800,
/// `810`.
/// Co-op vs. AI Intro Bot games on Twisted Treeline
///
/// Deprecated in patch 9.23
#[deprecated(note="Deprecated in patch 9.23")]
TWISTED_TREELINE_CO_OP_VS_AI_INTRO_BOT = 810,
/// `820`.
/// Co-op vs. AI Beginner Bot games on Twisted Treeline
TWISTED_TREELINE_CO_OP_VS_AI_BEGINNER_BOT = 820,
/// `830`.
/// Co-op vs. AI Intro Bot games on Summoner's Rift
///
/// Deprecated in March 2024 in favor of queueId 870
#[deprecated(note="Deprecated in March 2024 in favor of queueId 870")]
SUMMONERS_RIFT_CO_OP_VS_AI_INTRO_BOT_DEPRECATED_830 = 830,
/// `840`.
/// Co-op vs. AI Beginner Bot games on Summoner's Rift
///
/// Deprecated in March 2024 in favor of queueId 880
#[deprecated(note="Deprecated in March 2024 in favor of queueId 880")]
SUMMONERS_RIFT_CO_OP_VS_AI_BEGINNER_BOT_DEPRECATED_840 = 840,
/// `850`.
/// Co-op vs. AI Intermediate Bot games on Summoner's Rift
///
/// Deprecated in March 2024 in favor of queueId 890
#[deprecated(note="Deprecated in March 2024 in favor of queueId 890")]
SUMMONERS_RIFT_CO_OP_VS_AI_INTERMEDIATE_BOT_DEPRECATED_850 = 850,
/// `870`.
/// Co-op vs. AI Intro Bot games on Summoner's Rift
SUMMONERS_RIFT_CO_OP_VS_AI_INTRO_BOT = 870,
/// `880`.
/// Co-op vs. AI Beginner Bot games on Summoner's Rift
SUMMONERS_RIFT_CO_OP_VS_AI_BEGINNER_BOT = 880,
/// `890`.
/// Co-op vs. AI Intermediate Bot games on Summoner's Rift
SUMMONERS_RIFT_CO_OP_VS_AI_INTERMEDIATE_BOT = 890,
/// `900`.
/// ARURF games on Summoner's Rift
SUMMONERS_RIFT_ARURF = 900,
/// `910`.
/// Ascension games on Crystal Scar
CRYSTAL_SCAR_ASCENSION = 910,
/// `920`.
/// Legend of the Poro King games on Howling Abyss
HOWLING_ABYSS_LEGEND_OF_THE_PORO_KING = 920,
/// `940`.
/// Nexus Siege games on Summoner's Rift
SUMMONERS_RIFT_NEXUS_SIEGE = 940,
/// `950`.
/// Doom Bots Voting games on Summoner's Rift
SUMMONERS_RIFT_DOOM_BOTS_VOTING = 950,
/// `960`.
/// Doom Bots Standard games on Summoner's Rift
SUMMONERS_RIFT_DOOM_BOTS_STANDARD = 960,
/// `980`.
/// Star Guardian Invasion: Normal games on Valoran City Park
VALORAN_CITY_PARK_STAR_GUARDIAN_INVASION_NORMAL = 980,
/// `990`.
/// Star Guardian Invasion: Onslaught games on Valoran City Park
VALORAN_CITY_PARK_STAR_GUARDIAN_INVASION_ONSLAUGHT = 990,
/// `1000`.
/// PROJECT: Hunters games on Overcharge
OVERCHARGE_PROJECT_HUNTERS = 1000,
/// `1010`.
/// Snow ARURF games on Summoner's Rift
SUMMONERS_RIFT_SNOW_ARURF = 1010,
/// `1020`.
/// One for All games on Summoner's Rift
SUMMONERS_RIFT_ONE_FOR_ALL = 1020,
/// `1030`.
/// Odyssey Extraction: Intro games on Crash Site
CRASH_SITE_ODYSSEY_EXTRACTION_INTRO = 1030,
/// `1040`.
/// Odyssey Extraction: Cadet games on Crash Site
CRASH_SITE_ODYSSEY_EXTRACTION_CADET = 1040,
/// `1050`.
/// Odyssey Extraction: Crewmember games on Crash Site
CRASH_SITE_ODYSSEY_EXTRACTION_CREWMEMBER = 1050,
/// `1060`.
/// Odyssey Extraction: Captain games on Crash Site
CRASH_SITE_ODYSSEY_EXTRACTION_CAPTAIN = 1060,
/// `1070`.
/// Odyssey Extraction: Onslaught games on Crash Site
CRASH_SITE_ODYSSEY_EXTRACTION_ONSLAUGHT = 1070,
/// `1090`.
/// Teamfight Tactics games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS = 1090,
/// `1091`.
/// Teamfight Tactics 1v0 games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_1V0 = 1091,
/// `1092`.
/// Teamfight Tactics 2v0 games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_2V0 = 1092,
/// `1100`.
/// Ranked Teamfight Tactics games on Convergence
CONVERGENCE_RANKED_TEAMFIGHT_TACTICS = 1100,
/// `1110`.
/// Teamfight Tactics Tutorial games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_TUTORIAL = 1110,
/// `1111`.
/// Teamfight Tactics Simluation games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_SIMLUATION = 1111,
/// `1130`.
/// Ranked Teamfight Tactics (Hyper Roll) games on Convergence
CONVERGENCE_RANKED_TEAMFIGHT_TACTICS_HYPER_ROLL = 1130,
/// `1150`.
/// Ranked Teamfight Tactics (Double Up Workshop) games on Convergence
///
/// Deprecated in patch 12.11 in favor of queueId 1160
#[deprecated(note="Deprecated in patch 12.11 in favor of queueId 1160")]
CONVERGENCE_RANKED_TEAMFIGHT_TACTICS_DOUBLE_UP_WORKSHOP_DEPRECATED_1150 = 1150,
/// `1160`.
/// Ranked Teamfight Tactics (Double Up Workshop) games on Convergence
CONVERGENCE_RANKED_TEAMFIGHT_TACTICS_DOUBLE_UP_WORKSHOP = 1160,
/// `1200`.
/// Nexus Blitz games on Nexus Blitz
///
/// Deprecated in patch 9.2 in favor of queueId 1300
#[deprecated(note="Deprecated in patch 9.2 in favor of queueId 1300")]
NEXUS_BLITZ_DEPRECATED_1200 = 1200,
/// `1210`.
/// Teamfight Tactics (Choncc's Treasure) games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_CHONCCS_TREASURE = 1210,
/// `1300`.
/// Nexus Blitz games on Nexus Blitz
NEXUS_BLITZ = 1300,
/// `1400`.
/// Ultimate Spellbook games on Summoner's Rift
SUMMONERS_RIFT_ULTIMATE_SPELLBOOK = 1400,
/// `1700`.
/// 2v2v2v2 `CHERRY` games on Arena
ARENA_2V2V2V2_CHERRY = 1700,
/// `1710`.
/// Arena (`CHERRY` games) games on Rings of Wrath
RINGS_OF_WRATH_ARENA_CHERRY_GAMES = 1710,
/// `1810`.
/// Swarm solo (`STRAWBERRY` games) games on Swarm
SWARM_SOLO_STRAWBERRY_GAMES = 1810,
/// `1820`.
/// Swarm duo (`STRAWBERRY` games) games on Swarm
SWARM_DUO_STRAWBERRY_GAMES = 1820,
/// `1830`.
/// Swarm trio (`STRAWBERRY` games) games on Swarm
SWARM_TRIO_STRAWBERRY_GAMES = 1830,
/// `1840`.
/// Swarm quad (`STRAWBERRY` games) games on Swarm
SWARM_QUAD_STRAWBERRY_GAMES = 1840,
/// `1900`.
/// Pick URF games on Summoner's Rift
SUMMONERS_RIFT_PICK_URF = 1900,
/// `2000`.
/// Tutorial 1 games on Summoner's Rift
SUMMONERS_RIFT_TUTORIAL_1 = 2000,
/// `2010`.
/// Tutorial 2 games on Summoner's Rift
SUMMONERS_RIFT_TUTORIAL_2 = 2010,
/// `2020`.
/// Tutorial 3 games on Summoner's Rift
SUMMONERS_RIFT_TUTORIAL_3 = 2020,
/// `6000`.
/// Teamfight Tactics Set 3.5 Revival games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_SET_3_5_REVIVAL = 6000,
/// `6100`.
/// Teamfight Tactics Revival: Festival of Beasts games on Convergence
CONVERGENCE_TEAMFIGHT_TACTICS_REVIVAL_FESTIVAL_OF_BEASTS = 6100,
}
}

View file

@ -0,0 +1,39 @@
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version: 996d171a2b79e9bb85c549f47b07c6ef2721fc8a
use strum_macros::{EnumString, EnumVariantNames, IntoStaticStr};
///LoL or TFT queue types.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(EnumString, EnumVariantNames, IntoStaticStr)]
#[repr(u8)]
pub enum QueueType {
/// Catch-all variant for new/unknown values.
#[strum(default)]
UNKNOWN(String),
///5v5 Ranked Solo games
RANKED_SOLO_5x5,
///5v5 Ranked Flex games
RANKED_FLEX_SR,
///3v3 Ranked Flex games
///
///Deprecated in patch 9.23
#[deprecated(note = "Deprecated in patch 9.23")]
RANKED_FLEX_TT,
///Ranked Teamfight Tactics games
RANKED_TFT,
///Ranked Teamfight Tactics (Hyper Roll) games
RANKED_TFT_TURBO,
///Ranked Teamfight Tactics (Double Up Workshop) games
///
///Deprecated in patch 12.11 in favor of queueId 1160 (`RANKED_TFT_DOUBLE_UP`)
#[deprecated(
note = "Deprecated in patch 12.11 in favor of queueId 1160 (`RANKED_TFT_DOUBLE_UP`)"
)]
RANKED_TFT_PAIRS,
///Ranked Teamfight Tactics (Double Up Workshop) games
RANKED_TFT_DOUBLE_UP,
///"Arena" games
CHERRY,
}
serde_strum_unknown!(QueueType);

View file

@ -1,48 +1,72 @@
#![cfg_attr(any(), rustfmt::skip)]
///////////////////////////////////////////////
// //
// ! //
// This file is automatically generated! //
// Do not directly edit! //
// //
///////////////////////////////////////////////
use strum_macros::{ EnumString, EnumVariantNames, IntoStaticStr };
/// LoL or TFT ranked queue types.
#[non_exhaustive]
#[derive(Debug, Clone)]
#[derive(Eq, PartialEq, Hash)]
#[derive(EnumString, EnumVariantNames, IntoStaticStr)]
#[repr(u8)]
pub enum QueueType {
/// Catch-all variant for new, unknown queue types.
#[strum(default)]
UNKNOWN(String),
/// 5v5 Ranked Solo games
RANKED_SOLO_5x5,
/// 5v5 Ranked Flex games
RANKED_FLEX_SR,
/// 3v3 Ranked Flex games
/// Deprecated in patch 9.23
#[deprecated(note="Deprecated in patch 9.23")]
RANKED_FLEX_TT,
/// Ranked Teamfight Tactics games
RANKED_TFT,
/// Ranked Teamfight Tactics (Hyper Roll) games
RANKED_TFT_TURBO,
/// Ranked Teamfight Tactics (Double Up Workshop) games
/// Deprecated in patch 12.11 in favor of queueId 1160 (`RANKED_TFT_DOUBLE_UP`)
#[deprecated(note="Deprecated in patch 12.11 in favor of queueId 1160 (`RANKED_TFT_DOUBLE_UP`)")]
RANKED_TFT_PAIRS,
/// Ranked Teamfight Tactics (Double Up Workshop) games
RANKED_TFT_DOUBLE_UP,
/// "Arena" games
CHERRY,
}
serde_strum_unknown!(QueueType);
include_autogen!("queue_type.gen.rs");
#[cfg(test)]
mod test;
mod test {
use super::*;
#[test]
fn check_as_ref() {
assert_eq!("RANKED_SOLO_5x5", QueueType::RANKED_SOLO_5x5.as_ref());
}
#[test]
fn check_to_string() {
assert_eq!("RANKED_SOLO_5x5", QueueType::RANKED_SOLO_5x5.to_string());
}
#[test]
fn check_from_string() {
assert_eq!(QueueType::RANKED_SOLO_5x5, "RANKED_SOLO_5x5".into());
assert_eq!(
QueueType::UNKNOWN("RANKED_MYSTERY_UNKNOWN".to_owned()),
"RANKED_MYSTERY_UNKNOWN".into()
);
assert_eq!(
"RANKED_MYSTERY_UNKNOWN",
QueueType::UNKNOWN("RANKED_MYSTERY_UNKNOWN".to_owned()).as_ref()
);
}
#[test]
fn check_serialize() {
assert_eq!(
Some("\"RANKED_TFT_DOUBLE_UP\""),
serde_json::to_string(&QueueType::RANKED_TFT_DOUBLE_UP)
.ok()
.as_deref()
);
assert_eq!(
Some("\"RANKED_MYSTERY_UNKNOWN\""),
serde_json::to_string(&QueueType::UNKNOWN("RANKED_MYSTERY_UNKNOWN".to_owned()))
.ok()
.as_deref()
);
}
#[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;
let dict: BTreeMap<usize, QueueType> = serde_json::from_str(
r#"{
"100": "RANKED_SOLO_5x5",
"200": "RANKED_TFT_TURBO",
"210": "RANKED_TFT_DOUBLE_UP",
"211": "RANKED_TFT_PAIRS",
"900": "RANKED_MYSTERY_UNKNOWN"
}"#,
)
.unwrap();
assert_eq!(Some(&QueueType::RANKED_SOLO_5x5), dict.get(&100));
assert_eq!(Some(&QueueType::RANKED_TFT_TURBO), dict.get(&200));
assert_eq!(Some(&QueueType::RANKED_TFT_DOUBLE_UP), dict.get(&210));
assert_eq!(Some(&QueueType::RANKED_TFT_PAIRS), dict.get(&211));
assert_eq!(
Some(&QueueType::UNKNOWN("RANKED_MYSTERY_UNKNOWN".to_owned())),
dict.get(&900)
);
}
}

View file

@ -1,52 +0,0 @@
use super::*;
#[test]
fn check_as_ref() {
assert_eq!("RANKED_SOLO_5x5", QueueType::RANKED_SOLO_5x5.as_ref());
}
#[test]
fn check_to_string() {
assert_eq!("RANKED_SOLO_5x5", QueueType::RANKED_SOLO_5x5.to_string());
}
#[test]
fn check_from_string() {
assert_eq!(QueueType::RANKED_SOLO_5x5, "RANKED_SOLO_5x5".into());
assert_eq!(QueueType::UNKNOWN("RANKED_MYSTERY_UNKNOWN".to_owned()), "RANKED_MYSTERY_UNKNOWN".into());
assert_eq!("RANKED_MYSTERY_UNKNOWN", QueueType::UNKNOWN("RANKED_MYSTERY_UNKNOWN".to_owned()).as_ref());
}
#[test]
fn check_serialize() {
assert_eq!(Some("\"RANKED_TFT_DOUBLE_UP\""),
serde_json::to_string(&QueueType::RANKED_TFT_DOUBLE_UP)
.ok().as_deref());
assert_eq!(Some("\"RANKED_MYSTERY_UNKNOWN\""),
serde_json::to_string(&QueueType::UNKNOWN("RANKED_MYSTERY_UNKNOWN".to_owned()))
.ok().as_deref());
}
#[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;
let dict: BTreeMap<usize, QueueType> = serde_json::from_str(
r#"{
"100": "RANKED_SOLO_5x5",
"200": "RANKED_TFT_TURBO",
"210": "RANKED_TFT_DOUBLE_UP",
"211": "RANKED_TFT_PAIRS",
"900": "RANKED_MYSTERY_UNKNOWN"
}"#
).unwrap();
assert_eq!(Some(&QueueType::RANKED_SOLO_5x5), dict.get(&100));
assert_eq!(Some(&QueueType::RANKED_TFT_TURBO), dict.get(&200));
assert_eq!(Some(&QueueType::RANKED_TFT_DOUBLE_UP), dict.get(&210));
assert_eq!(Some(&QueueType::RANKED_TFT_PAIRS), dict.get(&211));
assert_eq!(Some(&QueueType::UNKNOWN("RANKED_MYSTERY_UNKNOWN".to_owned())), dict.get(&900));
}

View file

@ -0,0 +1,352 @@
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version: 996d171a2b79e9bb85c549f47b07c6ef2721fc8a
use num_enum::{IntoPrimitive, TryFromPrimitive};
use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};
///Regional routes, used in tournament services, Legends of Runeterra (LoR), and some other endpoints.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[repr(u8)]
#[non_exhaustive]
pub enum RegionalRoute {
///North and South America.
///
///`1` (riotapi-schema ID/repr)
#[strum(to_string = "AMERICAS")]
AMERICAS = 1,
///Asia, used for LoL matches (`match-v5`) and TFT matches (`tft-match-v1`).
///
///`2` (riotapi-schema ID/repr)
#[strum(to_string = "ASIA")]
ASIA = 2,
///Europe.
///
///`3` (riotapi-schema ID/repr)
#[strum(to_string = "EUROPE")]
EUROPE = 3,
///South East Asia, used for LoR, LoL matches (`match-v5`), and TFT matches (`tft-match-v1`).
///
///`4` (riotapi-schema ID/repr)
#[strum(to_string = "SEA")]
SEA = 4,
///Asia-Pacific, deprecated, for some old matches in `lor-match-v1`.
///
///`10` (riotapi-schema ID/repr)
#[deprecated]
#[strum(to_string = "APAC")]
APAC = 10,
///Special esports platform for `account-v1`. Do not confuse with the `esports` Valorant platform route.
///
///`11` (riotapi-schema ID/repr)
#[strum(to_string = "ESPORTS")]
ESPORTS = 11,
///Special Europe esports platform for `account-v1`. Do not confuse with the `esports` Valorant platform route.
///
///`12` (riotapi-schema ID/repr)
#[strum(to_string = "ESPORTSEU")]
ESPORTSEU = 12,
}
///Platform routes for League of Legends (LoL), Teamfight Tactics (TFT), and Legends of Runeterra (LoR).
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[repr(u8)]
#[non_exhaustive]
pub enum PlatformRoute {
///Brazil.
///
///`16` (riotapi-schema ID/repr)
#[strum(to_string = "BR1", serialize = "BR")]
BR1 = 16,
///Europe, Northeast.
///
///`17` (riotapi-schema ID/repr)
#[strum(to_string = "EUN1", serialize = "EUNE")]
EUN1 = 17,
///Europe, West.
///
///`18` (riotapi-schema ID/repr)
#[strum(to_string = "EUW1", serialize = "EUW")]
EUW1 = 18,
///Japan.
///
///`19` (riotapi-schema ID/repr)
#[strum(to_string = "JP1", serialize = "JP")]
JP1 = 19,
///Korea.
///
///`20` (riotapi-schema ID/repr)
#[strum(to_string = "KR")]
KR = 20,
///Latin America, North.
///
///`21` (riotapi-schema ID/repr)
#[strum(to_string = "LA1", serialize = "LAN")]
LA1 = 21,
///Latin America, South.
///
///`22` (riotapi-schema ID/repr)
#[strum(to_string = "LA2", serialize = "LAS")]
LA2 = 22,
///Middle East and North Africa.
///
///`37` (riotapi-schema ID/repr)
#[strum(to_string = "ME1", serialize = "MENA")]
ME1 = 37,
///North America.
///
///`23` (riotapi-schema ID/repr)
#[strum(to_string = "NA1", serialize = "NA")]
NA1 = 23,
///Oceania.
///
///`24` (riotapi-schema ID/repr)
#[strum(to_string = "OC1", serialize = "OCE")]
OC1 = 24,
///Philippines, moved into `sg2` on 2025-01-08.
///
///`32` (riotapi-schema ID/repr)
#[deprecated]
#[strum(to_string = "PH2", serialize = "PH")]
PH2 = 32,
///Russia
///
///`25` (riotapi-schema ID/repr)
#[strum(to_string = "RU")]
RU = 25,
///Singapore, Thailand, Philippines
///
///`33` (riotapi-schema ID/repr)
#[strum(to_string = "SG2", serialize = "SG")]
SG2 = 33,
///Thailand, moved into `sg2` on 2025-01-08.
///
///`34` (riotapi-schema ID/repr)
#[deprecated]
#[strum(to_string = "TH2", serialize = "TH")]
TH2 = 34,
///Turkey
///
///`26` (riotapi-schema ID/repr)
#[strum(to_string = "TR1", serialize = "TR")]
TR1 = 26,
///Taiwan
///
///`35` (riotapi-schema ID/repr)
#[strum(to_string = "TW2", serialize = "TW")]
TW2 = 35,
///Vietnam
///
///`36` (riotapi-schema ID/repr)
#[strum(to_string = "VN2", serialize = "VN")]
VN2 = 36,
///Public Beta Environment, special beta testing platform. Located in North America.
///
///`31` (riotapi-schema ID/repr)
#[strum(to_string = "PBE1", serialize = "PBE")]
PBE1 = 31,
}
impl PlatformRoute {
/// Converts this [`PlatformRoute`] into its corresponding
/// [`RegionalRoute`] for LoL and TFT match endpoints such as
/// [`match-v5`](crate::endpoints::MatchV5).
pub fn to_regional(self) -> RegionalRoute {
match self {
Self::BR1 => RegionalRoute::AMERICAS,
Self::EUN1 => RegionalRoute::EUROPE,
Self::EUW1 => RegionalRoute::EUROPE,
Self::JP1 => RegionalRoute::ASIA,
Self::KR => RegionalRoute::ASIA,
Self::LA1 => RegionalRoute::AMERICAS,
Self::LA2 => RegionalRoute::AMERICAS,
Self::ME1 => RegionalRoute::EUROPE,
Self::NA1 => RegionalRoute::AMERICAS,
Self::OC1 => RegionalRoute::SEA,
Self::PH2 => RegionalRoute::SEA,
Self::RU => RegionalRoute::EUROPE,
Self::SG2 => RegionalRoute::SEA,
Self::TH2 => RegionalRoute::SEA,
Self::TR1 => RegionalRoute::EUROPE,
Self::TW2 => RegionalRoute::SEA,
Self::VN2 => RegionalRoute::SEA,
Self::PBE1 => RegionalRoute::AMERICAS,
}
}
/// Converts this [`PlatformRoute`] into its corresponding
/// [`RegionalRoute`] for LoR endpoints such as
/// [`lor-match-v1`](crate::endpoints::LorMatchV1).
pub fn to_regional_lor(self) -> RegionalRoute {
match self {
Self::BR1 => RegionalRoute::AMERICAS,
Self::EUN1 => RegionalRoute::EUROPE,
Self::EUW1 => RegionalRoute::EUROPE,
Self::JP1 => RegionalRoute::ASIA,
Self::KR => RegionalRoute::ASIA,
Self::LA1 => RegionalRoute::AMERICAS,
Self::LA2 => RegionalRoute::AMERICAS,
Self::ME1 => RegionalRoute::EUROPE,
Self::NA1 => RegionalRoute::AMERICAS,
Self::OC1 => RegionalRoute::SEA,
Self::PH2 => RegionalRoute::SEA,
Self::RU => RegionalRoute::SEA,
Self::SG2 => RegionalRoute::SEA,
Self::TH2 => RegionalRoute::SEA,
Self::TR1 => RegionalRoute::SEA,
Self::TW2 => RegionalRoute::SEA,
Self::VN2 => RegionalRoute::SEA,
Self::PBE1 => RegionalRoute::AMERICAS,
}
}
/// Used in the LoL Tournament API. Specifically
/// [`tournament-stub-v5.registerProviderData`](crate::endpoints::TournamentStubV5::register_provider_data)
/// and [`tournament-v5.registerProviderData`](crate::endpoints::TournamentV5::register_provider_data).
///
/// Returns `None` if the corresponding tournament region is unknown: <https://github.com/MingweiSamuel/riotapi-schema/issues/58>.
pub fn to_tournament_region(self) -> Option<TournamentRegion> {
match self {
Self::BR1 => Some(TournamentRegion::BR),
Self::EUN1 => Some(TournamentRegion::EUNE),
Self::EUW1 => Some(TournamentRegion::EUW),
Self::JP1 => Some(TournamentRegion::JP),
Self::KR => None,
Self::LA1 => Some(TournamentRegion::LAN),
Self::LA2 => Some(TournamentRegion::LAS),
Self::ME1 => None,
Self::NA1 => Some(TournamentRegion::NA),
Self::OC1 => Some(TournamentRegion::OCE),
Self::PH2 => None,
Self::RU => None,
Self::SG2 => None,
Self::TH2 => None,
Self::TR1 => Some(TournamentRegion::TR),
Self::TW2 => None,
Self::VN2 => None,
Self::PBE1 => Some(TournamentRegion::PBE),
}
}
/// Get the slightly more human-friendly alternate name for this `PlatformRoute`. Specifically
/// excludes any trailing numbers and appends extra N(orth), S(outh), E(ast), and/or W(est)
/// suffixes to some names. Some of these are old region names which are often still used as
/// user-facing names, e.g. on op.gg.
///
/// Note these strings *are* handled by the `FromStr` implementation, if you wish to parse them
/// back into `PlatformRoute`s.
pub fn as_region_str(self) -> &'static str {
match self {
Self::BR1 => "BR",
Self::EUN1 => "EUNE",
Self::EUW1 => "EUW",
Self::JP1 => "JP",
Self::KR => "KR",
Self::LA1 => "LAN",
Self::LA2 => "LAS",
Self::ME1 => "MENA",
Self::NA1 => "NA",
Self::OC1 => "OCE",
Self::PH2 => "PH",
Self::RU => "RU",
Self::SG2 => "SG",
Self::TH2 => "TH",
Self::TR1 => "TR",
Self::TW2 => "TW",
Self::VN2 => "VN",
Self::PBE1 => "PBE",
}
}
}
///Platform routes for Valorant.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[repr(u8)]
#[non_exhaustive]
pub enum ValPlatformRoute {
///Asia-Pacific.
///
///`64` (riotapi-schema ID/repr)
#[strum(to_string = "AP")]
AP = 64,
///Brazil.
///
///`65` (riotapi-schema ID/repr)
#[strum(to_string = "BR")]
BR = 65,
///Europe.
///
///`66` (riotapi-schema ID/repr)
#[strum(to_string = "EU")]
EU = 66,
///Korea.
///
///`70` (riotapi-schema ID/repr)
#[strum(to_string = "KR")]
KR = 70,
///Latin America.
///
///`68` (riotapi-schema ID/repr)
#[strum(to_string = "LATAM")]
LATAM = 68,
///North America.
///
///`69` (riotapi-schema ID/repr)
#[strum(to_string = "NA")]
NA = 69,
///Special esports platform.
///
///`95` (riotapi-schema ID/repr)
#[strum(to_string = "ESPORTS")]
ESPORTS = 95,
}
/// Tournament regions for League of Legends (LoL) used in
/// [`TournamentStubV5`](crate::endpoints::TournamentStubV5)
/// and [`TournamentV5`](crate::endpoints::TournamentV5).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[derive(serde::Serialize, crate::de::Deserialize)]
#[repr(u8)]
#[non_exhaustive]
pub enum TournamentRegion {
///Brazil.
///
///`16` (riotapi-schema ID/repr)
BR = 16,
///Europe, Northeast.
///
///`17` (riotapi-schema ID/repr)
EUNE = 17,
///Europe, West.
///
///`18` (riotapi-schema ID/repr)
EUW = 18,
///Japan.
///
///`19` (riotapi-schema ID/repr)
JP = 19,
///Latin America, North.
///
///`21` (riotapi-schema ID/repr)
LAN = 21,
///Latin America, South.
///
///`22` (riotapi-schema ID/repr)
LAS = 22,
///North America.
///
///`23` (riotapi-schema ID/repr)
NA = 23,
///Oceania.
///
///`24` (riotapi-schema ID/repr)
OCE = 24,
///Turkey
///
///`26` (riotapi-schema ID/repr)
TR = 26,
///Public Beta Environment, special beta testing platform. Located in North America.
///
///`31` (riotapi-schema ID/repr)
PBE = 31,
}

View file

@ -1,360 +1,200 @@
#![cfg_attr(any(), rustfmt::skip)]
///////////////////////////////////////////////
// //
// ! //
// This file is automatically generated! //
// Do not directly edit! //
// //
///////////////////////////////////////////////
#![allow(clippy::upper_case_acronyms)]
use num_enum::{ IntoPrimitive, TryFromPrimitive };
use strum_macros::{ EnumString, EnumIter, Display, IntoStaticStr };
include_autogen!("route.gen.rs");
/// Regional routes, used in tournament services, Legends of Runeterra (LoR), and other some endpoints.
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[derive(Clone, Copy)]
/// Utility enum containing all routing variants.
#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Copy)]
#[repr(u8)]
#[non_exhaustive]
pub enum RegionalRoute {
/// North and South America.
///
/// `1` (riotapi-schema ID/repr)
AMERICAS = 1,
/// Asia, used for LoL matches (`match-v5`) and TFT matches (`tft-match-v1`).
///
/// `2` (riotapi-schema ID/repr)
ASIA = 2,
/// Europe.
///
/// `3` (riotapi-schema ID/repr)
EUROPE = 3,
/// South East Asia, used for LoR, LoL matches (`match-v5`), and TFT matches (`tft-match-v1`).
///
/// `4` (riotapi-schema ID/repr)
SEA = 4,
/// Asia-Pacific, deprecated, for some old matches in `lor-match-v1`.
///
/// `10` (riotapi-schema ID/repr)
#[deprecated]
APAC = 10,
/// Special esports platform for `account-v1`. Do not confuse with the `esports` Valorant platform route.
///
/// `11` (riotapi-schema ID/repr)
ESPORTS = 11,
/// Special Europe esports platform for `account-v1`. Do not confuse with the `esports` Valorant platform route.
///
/// `12` (riotapi-schema ID/repr)
ESPORTSEU = 12,
pub enum Route {
/// Sub-variant for [`RegionalRoute`]s.
Regional(RegionalRoute),
/// Sub-variant for [`PlatformRoute`]s.
Platform(PlatformRoute),
/// Sub-variant for [`ValPlatformRoute`]s.
ValPlatform(ValPlatformRoute),
}
/// Platform routes for League of Legends (LoL), Teamfight Tactics (TFT), and Legends of Runeterra (LoR).
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[derive(Clone, Copy)]
#[repr(u8)]
#[non_exhaustive]
// Note: strum(serialize = ...) actually specifies extra DEserialization values.
pub enum PlatformRoute {
/// Brazil.
///
/// `16` (riotapi-schema ID/repr)
#[strum(to_string="BR1", serialize="BR")]
BR1 = 16,
/// Europe, Northeast.
///
/// `17` (riotapi-schema ID/repr)
#[strum(to_string="EUN1", serialize="EUNE")]
EUN1 = 17,
/// Europe, West.
///
/// `18` (riotapi-schema ID/repr)
#[strum(to_string="EUW1", serialize="EUW")]
EUW1 = 18,
/// Japan.
///
/// `19` (riotapi-schema ID/repr)
#[strum(to_string="JP1", serialize="JP")]
JP1 = 19,
/// Korea.
///
/// `20` (riotapi-schema ID/repr)
KR = 20,
/// Latin America, North.
///
/// `21` (riotapi-schema ID/repr)
#[strum(to_string="LA1", serialize="LAN")]
LA1 = 21,
/// Latin America, South.
///
/// `22` (riotapi-schema ID/repr)
#[strum(to_string="LA2", serialize="LAS")]
LA2 = 22,
/// Middle East and North Africa.
///
/// `37` (riotapi-schema ID/repr)
#[strum(to_string="ME1", serialize="MENA")]
ME1 = 37,
/// North America.
///
/// `23` (riotapi-schema ID/repr)
#[strum(to_string="NA1", serialize="NA")]
NA1 = 23,
/// Oceania.
///
/// `24` (riotapi-schema ID/repr)
#[strum(to_string="OC1", serialize="OCE")]
OC1 = 24,
/// Philippines, moved into `sg2` on 2025-01-08.
///
/// `32` (riotapi-schema ID/repr)
#[deprecated]
#[strum(to_string="PH2", serialize="PH")]
PH2 = 32,
/// Russia
///
/// `25` (riotapi-schema ID/repr)
RU = 25,
/// Singapore, Thailand, Philippines
///
/// `33` (riotapi-schema ID/repr)
#[strum(to_string="SG2", serialize="SG")]
SG2 = 33,
/// Thailand, moved into `sg2` on 2025-01-08.
///
/// `34` (riotapi-schema ID/repr)
#[deprecated]
#[strum(to_string="TH2", serialize="TH")]
TH2 = 34,
/// Turkey
///
/// `26` (riotapi-schema ID/repr)
#[strum(to_string="TR1", serialize="TR")]
TR1 = 26,
/// Taiwan
///
/// `35` (riotapi-schema ID/repr)
#[strum(to_string="TW2", serialize="TW")]
TW2 = 35,
/// Vietnam
///
/// `36` (riotapi-schema ID/repr)
#[strum(to_string="VN2", serialize="VN")]
VN2 = 36,
/// Public Beta Environment, special beta testing platform. Located in North America.
///
/// `31` (riotapi-schema ID/repr)
#[strum(to_string="PBE1", serialize="PBE")]
PBE1 = 31,
}
impl PlatformRoute {
/// Converts this [`PlatformRoute`] into its corresponding
/// [`RegionalRoute`] for LoL and TFT match endpoints.
/// For example, [`match-v5`](crate::endpoints::MatchV5).
pub fn to_regional(self) -> RegionalRoute {
match self {
Self::BR1 => RegionalRoute::AMERICAS,
Self::EUN1 => RegionalRoute::EUROPE,
Self::EUW1 => RegionalRoute::EUROPE,
Self::JP1 => RegionalRoute::ASIA,
Self::KR => RegionalRoute::ASIA,
Self::LA1 => RegionalRoute::AMERICAS,
Self::LA2 => RegionalRoute::AMERICAS,
Self::ME1 => RegionalRoute::EUROPE,
Self::NA1 => RegionalRoute::AMERICAS,
Self::OC1 => RegionalRoute::SEA,
Self::PH2 => RegionalRoute::SEA,
Self::RU => RegionalRoute::EUROPE,
Self::SG2 => RegionalRoute::SEA,
Self::TH2 => RegionalRoute::SEA,
Self::TR1 => RegionalRoute::EUROPE,
Self::TW2 => RegionalRoute::SEA,
Self::VN2 => RegionalRoute::SEA,
Self::PBE1 => RegionalRoute::AMERICAS,
}
}
/// Converts this [`PlatformRoute`] into its corresponding
/// [`RegionalRoute`] for LoR endpoints.
/// For example, [`lor-match-v1`](crate::endpoints::LorMatchV1).
pub fn to_regional_lor(self) -> RegionalRoute {
match self {
Self::BR1 => RegionalRoute::AMERICAS,
Self::EUN1 => RegionalRoute::EUROPE,
Self::EUW1 => RegionalRoute::EUROPE,
Self::JP1 => RegionalRoute::ASIA,
Self::KR => RegionalRoute::ASIA,
Self::LA1 => RegionalRoute::AMERICAS,
Self::LA2 => RegionalRoute::AMERICAS,
Self::ME1 => RegionalRoute::EUROPE,
Self::NA1 => RegionalRoute::AMERICAS,
Self::OC1 => RegionalRoute::SEA,
Self::PH2 => RegionalRoute::SEA,
Self::RU => RegionalRoute::SEA,
Self::SG2 => RegionalRoute::SEA,
Self::TH2 => RegionalRoute::SEA,
Self::TR1 => RegionalRoute::SEA,
Self::TW2 => RegionalRoute::SEA,
Self::VN2 => RegionalRoute::SEA,
Self::PBE1 => RegionalRoute::AMERICAS,
}
}
/// Used in the LoL Tournament API. Specifically
/// [`TournamentStubV5`](crate::endpoints::TournamentStubV5)/[`TournamentV5`](crate::endpoints::TournamentV5).
pub fn to_tournament_region(self) -> Option<TournamentRegion> {
match self {
Self::BR1 => Some(TournamentRegion::BR),
Self::EUN1 => Some(TournamentRegion::EUNE),
Self::EUW1 => Some(TournamentRegion::EUW),
Self::JP1 => Some(TournamentRegion::JP),
Self::LA1 => Some(TournamentRegion::LAN),
Self::LA2 => Some(TournamentRegion::LAS),
Self::NA1 => Some(TournamentRegion::NA),
Self::OC1 => Some(TournamentRegion::OCE),
Self::TR1 => Some(TournamentRegion::TR),
Self::PBE1 => Some(TournamentRegion::PBE),
_other => None,
}
}
/// Get the slightly more human-friendly alternate name for this `PlatformRoute`. Specifically
/// excludes any trailing numbers and appends extra N(orth), S(outh), E(ast), and/or W(est)
/// suffixes to some names. Some of these are old region names which are often still used as
/// user-facing names, e.g. on op.gg.
///
/// Note these strings *are* handled by the `FromStr` implementation, if you wish to parse them
/// back into `PlatformRoute`s.
pub fn as_region_str(self) -> &'static str {
match self {
Self::BR1 => "BR",
Self::EUN1 => "EUNE",
Self::EUW1 => "EUW",
Self::JP1 => "JP",
Self::LA1 => "LAN",
Self::LA2 => "LAS",
Self::ME1 => "MENA",
Self::NA1 => "NA",
Self::OC1 => "OCE",
Self::PH2 => "PH",
Self::SG2 => "SG",
Self::TH2 => "TH",
Self::TR1 => "TR",
Self::TW2 => "TW",
Self::VN2 => "VN",
Self::PBE1 => "PBE",
other => other.into(),
impl From<Route> for &'static str {
fn from(route: Route) -> Self {
match route {
Route::Regional(r) => r.into(),
Route::Platform(r) => r.into(),
Route::ValPlatform(r) => r.into(),
}
}
}
/// Platform routes for Valorant.
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[derive(Clone, Copy)]
#[repr(u8)]
#[non_exhaustive]
pub enum ValPlatformRoute {
/// Asia-Pacific.
///
/// `64` (riotapi-schema ID/repr)
AP = 64,
/// Brazil.
///
/// `65` (riotapi-schema ID/repr)
BR = 65,
/// Europe.
///
/// `66` (riotapi-schema ID/repr)
EU = 66,
/// Korea.
///
/// `70` (riotapi-schema ID/repr)
KR = 70,
/// Latin America.
///
/// `68` (riotapi-schema ID/repr)
LATAM = 68,
/// North America.
///
/// `69` (riotapi-schema ID/repr)
NA = 69,
/// Special esports platform.
///
/// `95` (riotapi-schema ID/repr)
ESPORTS = 95,
impl From<Route> for u8 {
fn from(route: Route) -> Self {
match route {
Route::Regional(r) => r.into(),
Route::Platform(r) => r.into(),
Route::ValPlatform(r) => r.into(),
}
}
}
/// Tournament regions for League of Legends (LoL) used in
/// [`TournamentStubV5`](crate::endpoints::TournamentStubV5)/[`TournamentV5`](crate::endpoints::TournamentV5).
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[derive(serde::Serialize, crate::de::Deserialize)]
#[derive(Clone, Copy)]
#[repr(u8)]
#[non_exhaustive]
// Note: strum(serialize = ...) actually specifies extra DEserialization values.
pub enum TournamentRegion {
/// Brazil.
BR = 16,
/// Europe, Northeast.
EUNE = 17,
/// Europe, West.
EUW = 18,
/// Japan.
JP = 19,
/// Latin America, North.
LAN = 21,
/// Latin America, South.
LAS = 22,
/// North America.
NA = 23,
/// Oceania.
OCE = 24,
/// Turkey
TR = 26,
/// Public Beta Environment, special beta testing platform. Located in North America.
PBE = 31,
impl num_enum::TryFromPrimitive for Route {
type Primitive = u8;
const NAME: &'static str = stringify!(Route);
fn try_from_primitive(
number: Self::Primitive,
) -> Result<Self, num_enum::TryFromPrimitiveError<Self>> {
RegionalRoute::try_from_primitive(number)
.map(Route::Regional)
.or_else(|_| PlatformRoute::try_from_primitive(number).map(Route::Platform))
.or_else(|_| ValPlatformRoute::try_from_primitive(number).map(Route::ValPlatform))
.map_err(|_| num_enum::TryFromPrimitiveError { number })
}
}
impl std::convert::TryFrom<u8> for Route {
type Error = num_enum::TryFromPrimitiveError<Self>;
fn try_from(number: u8) -> Result<Self, num_enum::TryFromPrimitiveError<Self>> {
<Self as num_enum::TryFromPrimitive>::try_from_primitive(number)
}
}
impl std::fmt::Display for Route {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Regional(r) => r.fmt(f),
Self::Platform(r) => r.fmt(f),
Self::ValPlatform(r) => r.fmt(f),
}
}
}
impl std::str::FromStr for Route {
type Err = strum::ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
RegionalRoute::from_str(s)
.map(Self::Regional)
.or_else(|_| PlatformRoute::from_str(s).map(Self::Platform))
.or_else(|_| ValPlatformRoute::from_str(s).map(Self::ValPlatform))
.map_err(|_| strum::ParseError::VariantNotFound)
}
}
impl Route {
/// Returns an iterator over all routes. Starts with [`Self::Regional`],
/// then [`Self::Platform`], and finally [`Self::ValPlatform`].
pub fn iter() -> impl Iterator<Item = Self> {
use strum::IntoEnumIterator;
let regional = RegionalRoute::iter().map(Self::Regional);
let platform = PlatformRoute::iter().map(Self::Platform);
let val_platform = ValPlatformRoute::iter().map(Self::ValPlatform);
regional.chain(platform).chain(val_platform)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_route_tostring() {
assert_eq!(
"AMERICAS",
Into::<&'static str>::into(Route::Regional(RegionalRoute::AMERICAS))
);
assert_eq!(
"KR",
Into::<&'static str>::into(Route::Platform(PlatformRoute::KR))
);
assert_eq!(
"KR",
Into::<&'static str>::into(Route::ValPlatform(ValPlatformRoute::KR))
);
}
#[test]
fn test_route_iter() {
for (i, route) in Route::iter().enumerate() {
println!("{:>2} {:<10} {:>3}", i, route, u8::from(route));
}
}
#[test]
fn test_route_tryfrom() {
for x in u8::MIN..=u8::MAX {
if let Ok(route) = std::convert::TryInto::<Route>::try_into(x) {
println!("{:>3} {:<8}", x, route);
}
}
}
#[test]
fn test_regional_tostring() {
assert_eq!("AMERICAS", RegionalRoute::AMERICAS.to_string());
assert_eq!("SEA", RegionalRoute::SEA.to_string());
assert_eq!(
"AMERICAS",
Into::<&'static str>::into(RegionalRoute::AMERICAS)
);
assert_eq!("SEA", Into::<&'static str>::into(RegionalRoute::SEA));
}
#[test]
fn test_regional_parse() {
assert_eq!(Ok(RegionalRoute::AMERICAS), "AMERICAS".parse());
assert_eq!(Ok(RegionalRoute::SEA), "SEA".parse());
assert!("NA".parse::<RegionalRoute>().is_err());
}
#[test]
fn test_platform_tostring() {
assert_eq!("BR1", PlatformRoute::BR1.to_string());
assert_eq!("KR", PlatformRoute::KR.to_string());
assert_eq!("BR1", Into::<&'static str>::into(PlatformRoute::BR1));
assert_eq!("KR", Into::<&'static str>::into(PlatformRoute::KR));
}
#[test]
fn test_platform_parse() {
assert_eq!(Ok(PlatformRoute::BR1), "BR1".parse());
assert_eq!(Ok(PlatformRoute::KR), "KR".parse());
assert_eq!(Ok(PlatformRoute::JP1), "JP1".parse());
assert_eq!(Ok(PlatformRoute::JP1), "JP".parse());
assert_eq!(Ok(PlatformRoute::NA1), "NA1".parse());
assert_eq!(Ok(PlatformRoute::NA1), "NA".parse());
assert!("LA".parse::<PlatformRoute>().is_err());
}
#[test]
fn test_valplatform_tostring() {
assert_eq!("AP", ValPlatformRoute::AP.to_string());
assert_eq!("KR", ValPlatformRoute::KR.to_string());
assert_eq!("ESPORTS", ValPlatformRoute::ESPORTS.to_string());
assert_eq!("AP", Into::<&'static str>::into(ValPlatformRoute::AP));
assert_eq!("KR", Into::<&'static str>::into(ValPlatformRoute::KR));
assert_eq!(
"ESPORTS",
Into::<&'static str>::into(ValPlatformRoute::ESPORTS)
);
}
#[test]
fn test_valplatform_parse() {
assert_eq!(Ok(ValPlatformRoute::AP), "AP".parse());
assert_eq!(Ok(ValPlatformRoute::KR), "KR".parse());
assert_eq!(Ok(ValPlatformRoute::ESPORTS), "ESPORTS".parse());
assert!("SEA".parse::<ValPlatformRoute>().is_err());
}
#[test]
fn test_tournament_region_serde() {
use crate::consts::TournamentRegion;
let json = serde_json::to_string(&TournamentRegion::EUNE);
assert!(json.is_ok());
assert_eq!("\"EUNE\"", &*json.unwrap());
}
}

View file

@ -1,198 +0,0 @@
use super::{PlatformRoute, RegionalRoute, ValPlatformRoute};
/// Utility enum containing all routing variants.
#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Copy)]
#[repr(u8)]
#[non_exhaustive]
pub enum Route {
/// Sub-variant for [`RegionalRoute`]s.
Regional(RegionalRoute),
/// Sub-variant for [`PlatformRoute`]s.
Platform(PlatformRoute),
/// Sub-variant for [`ValPlatformRoute`]s.
ValPlatform(ValPlatformRoute),
}
impl From<Route> for &'static str {
fn from(route: Route) -> Self {
match route {
Route::Regional(r) => r.into(),
Route::Platform(r) => r.into(),
Route::ValPlatform(r) => r.into(),
}
}
}
impl From<Route> for u8 {
fn from(route: Route) -> Self {
match route {
Route::Regional(r) => r.into(),
Route::Platform(r) => r.into(),
Route::ValPlatform(r) => r.into(),
}
}
}
impl num_enum::TryFromPrimitive for Route {
type Primitive = u8;
const NAME: &'static str = stringify!(Route);
fn try_from_primitive(
number: Self::Primitive,
) -> Result<Self, num_enum::TryFromPrimitiveError<Self>> {
RegionalRoute::try_from_primitive(number)
.map(Route::Regional)
.or_else(|_| PlatformRoute::try_from_primitive(number).map(Route::Platform))
.or_else(|_| ValPlatformRoute::try_from_primitive(number).map(Route::ValPlatform))
.map_err(|_| num_enum::TryFromPrimitiveError { number })
}
}
impl std::convert::TryFrom<u8> for Route {
type Error = num_enum::TryFromPrimitiveError<Self>;
fn try_from(number: u8) -> Result<Self, num_enum::TryFromPrimitiveError<Self>> {
<Self as num_enum::TryFromPrimitive>::try_from_primitive(number)
}
}
impl std::fmt::Display for Route {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Regional(r) => r.fmt(f),
Self::Platform(r) => r.fmt(f),
Self::ValPlatform(r) => r.fmt(f),
}
}
}
impl std::str::FromStr for Route {
type Err = strum::ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
RegionalRoute::from_str(s)
.map(Self::Regional)
.or_else(|_| PlatformRoute::from_str(s).map(Self::Platform))
.or_else(|_| ValPlatformRoute::from_str(s).map(Self::ValPlatform))
.map_err(|_| strum::ParseError::VariantNotFound)
}
}
impl Route {
/// Returns an iterator over all routes. Starts with [`Self::Regional`],
/// then [`Self::Platform`], and finally [`Self::ValPlatform`].
pub fn iter() -> impl Iterator<Item = Self> {
use strum::IntoEnumIterator;
let regional = RegionalRoute::iter().map(Self::Regional);
let platform = PlatformRoute::iter().map(Self::Platform);
let val_platform = ValPlatformRoute::iter().map(Self::ValPlatform);
regional.chain(platform).chain(val_platform)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_route_tostring() {
assert_eq!(
"AMERICAS",
Into::<&'static str>::into(Route::Regional(RegionalRoute::AMERICAS))
);
assert_eq!(
"KR",
Into::<&'static str>::into(Route::Platform(PlatformRoute::KR))
);
assert_eq!(
"KR",
Into::<&'static str>::into(Route::ValPlatform(ValPlatformRoute::KR))
);
}
#[test]
fn test_route_iter() {
for (i, route) in Route::iter().enumerate() {
println!("{:>2} {:<10} {:>3}", i, route, u8::from(route));
}
}
#[test]
fn test_route_tryfrom() {
for x in u8::MIN..=u8::MAX {
if let Ok(route) = std::convert::TryInto::<Route>::try_into(x) {
println!("{:>3} {:<8}", x, route);
}
}
}
#[test]
fn test_regional_tostring() {
assert_eq!("AMERICAS", RegionalRoute::AMERICAS.to_string());
assert_eq!("SEA", RegionalRoute::SEA.to_string());
assert_eq!(
"AMERICAS",
Into::<&'static str>::into(RegionalRoute::AMERICAS)
);
assert_eq!("SEA", Into::<&'static str>::into(RegionalRoute::SEA));
}
#[test]
fn test_regional_parse() {
assert_eq!(Ok(RegionalRoute::AMERICAS), "AMERICAS".parse());
assert_eq!(Ok(RegionalRoute::SEA), "SEA".parse());
assert!("NA".parse::<RegionalRoute>().is_err());
}
#[test]
fn test_platform_tostring() {
assert_eq!("BR1", PlatformRoute::BR1.to_string());
assert_eq!("KR", PlatformRoute::KR.to_string());
assert_eq!("BR1", Into::<&'static str>::into(PlatformRoute::BR1));
assert_eq!("KR", Into::<&'static str>::into(PlatformRoute::KR));
}
#[test]
fn test_platform_parse() {
assert_eq!(Ok(PlatformRoute::BR1), "BR1".parse());
assert_eq!(Ok(PlatformRoute::KR), "KR".parse());
assert_eq!(Ok(PlatformRoute::JP1), "JP1".parse());
assert_eq!(Ok(PlatformRoute::JP1), "JP".parse());
assert_eq!(Ok(PlatformRoute::NA1), "NA1".parse());
assert_eq!(Ok(PlatformRoute::NA1), "NA".parse());
assert!("LA".parse::<PlatformRoute>().is_err());
}
#[test]
fn test_valplatform_tostring() {
assert_eq!("AP", ValPlatformRoute::AP.to_string());
assert_eq!("KR", ValPlatformRoute::KR.to_string());
assert_eq!("ESPORTS", ValPlatformRoute::ESPORTS.to_string());
assert_eq!("AP", Into::<&'static str>::into(ValPlatformRoute::AP));
assert_eq!("KR", Into::<&'static str>::into(ValPlatformRoute::KR));
assert_eq!(
"ESPORTS",
Into::<&'static str>::into(ValPlatformRoute::ESPORTS)
);
}
#[test]
fn test_valplatform_parse() {
assert_eq!(Ok(ValPlatformRoute::AP), "AP".parse());
assert_eq!(Ok(ValPlatformRoute::KR), "KR".parse());
assert_eq!(Ok(ValPlatformRoute::ESPORTS), "ESPORTS".parse());
assert!("SEA".parse::<ValPlatformRoute>().is_err());
}
#[test]
fn test_tournament_region_serde() {
use crate::consts::TournamentRegion;
let json = serde_json::to_string(&TournamentRegion::EUNE);
assert!(json.is_ok());
assert_eq!("\"EUNE\"", &*json.unwrap());
}
}

View file

@ -0,0 +1,41 @@
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version: 996d171a2b79e9bb85c549f47b07c6ef2721fc8a
#[macro_rules_attribute::apply(newtype_enum)]
#[repr(u8)]
///A League of Legends season for competitive matchmaking.
pub enum Season {
///`0`
PRESEASON_3 = 0,
///`1`
SEASON_3 = 1,
///`2`
PRESEASON_2014 = 2,
///`3`
SEASON_2014 = 3,
///`4`
PRESEASON_2015 = 4,
///`5`
SEASON_2015 = 5,
///`6`
PRESEASON_2016 = 6,
///`7`
SEASON_2016 = 7,
///`8`
PRESEASON_2017 = 8,
///`9`
SEASON_2017 = 9,
///`10`
PRESEASON_2018 = 10,
///`11`
SEASON_2018 = 11,
///`12`
PRESEASON_2019 = 12,
///`13`
SEASON_2019 = 13,
///`14`
PRESEASON_2020 = 14,
///`15`
SEASON_2020 = 15,
}

4430
riven/src/endpoints.gen.rs Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,15 @@
#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/", env!("CARGO_PKG_README")))]
#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/", env!("CARGO_PKG_README")))]
// Re-exported crates.
#[cfg(feature = "eserde")]
pub use eserde;
pub use {reqwest, serde, serde_json};
#[macro_use]
mod macros;
mod config;
pub use config::RiotApiConfig;
pub mod consts;

View file

@ -1,5 +1,3 @@
#![macro_use]
/// Macro for deriving `Serialize` and `Deserialize` for string enums with an
/// `UNKNOWN(String)` variant.
///
@ -88,8 +86,9 @@ macro_rules! arr {
/// ```
macro_rules! newtype_enum {
{
#[repr($repr:ident)]
$( #[$attr:meta] )*
$v:vis newtype_enum $name:ident($repr:ty) {
$v:vis enum $name:ident {
$(
$( #[$var_attr:meta] )*
$var_name:ident = $var_val:expr,
@ -205,3 +204,13 @@ macro_rules! impl_edeserialize {
)*
};
}
/// Include the given file from `OUT_DIR` if the `riven_autogen_outdir` feature is enabled, otherwise from the current dir.
macro_rules! include_autogen {
($file:literal) => {
#[cfg(riven_autogen_outdir)]
include!(concat!(env!("OUT_DIR"), "/", $file));
#[cfg(not(riven_autogen_outdir))]
include!($file);
};
}

316
riven/src/meta.gen.rs Normal file
View file

@ -0,0 +1,316 @@
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version: 996d171a2b79e9bb85c549f47b07c6ef2721fc8a
use reqwest::Method;
/// Metadata for endpoints. Each tuple corresponds to one endpoint and contains
/// the HTTP [`Method`], `str` path, and the method's `str` ID.
pub static ALL_ENDPOINTS: [(Method, &str, &str); 87usize] = [
(Method::GET, "/riot/account/v1/accounts/by-puuid/{puuid}", "account-v1.getByPuuid"),
(
Method::GET,
"/riot/account/v1/accounts/by-riot-id/{gameName}/{tagLine}",
"account-v1.getByRiotId",
),
(Method::GET, "/riot/account/v1/accounts/me", "account-v1.getByAccessToken"),
(
Method::GET,
"/riot/account/v1/active-shards/by-game/{game}/by-puuid/{puuid}",
"account-v1.getActiveShard",
),
(
Method::GET,
"/lol/champion-mastery/v4/champion-masteries/by-puuid/{encryptedPUUID}",
"champion-mastery-v4.getAllChampionMasteriesByPUUID",
),
(
Method::GET,
"/lol/champion-mastery/v4/champion-masteries/by-puuid/{encryptedPUUID}/by-champion/{championId}",
"champion-mastery-v4.getChampionMasteryByPUUID",
),
(
Method::GET,
"/lol/champion-mastery/v4/champion-masteries/by-puuid/{encryptedPUUID}/top",
"champion-mastery-v4.getTopChampionMasteriesByPUUID",
),
(
Method::GET,
"/lol/champion-mastery/v4/scores/by-puuid/{encryptedPUUID}",
"champion-mastery-v4.getChampionMasteryScoreByPUUID",
),
(Method::GET, "/lol/platform/v3/champion-rotations", "champion-v3.getChampionInfo"),
(
Method::GET,
"/lol/clash/v1/players/by-puuid/{puuid}",
"clash-v1.getPlayersByPUUID",
),
(Method::GET, "/lol/clash/v1/teams/{teamId}", "clash-v1.getTeamById"),
(Method::GET, "/lol/clash/v1/tournaments", "clash-v1.getTournaments"),
(
Method::GET,
"/lol/clash/v1/tournaments/by-team/{teamId}",
"clash-v1.getTournamentByTeam",
),
(
Method::GET,
"/lol/clash/v1/tournaments/{tournamentId}",
"clash-v1.getTournamentById",
),
(
Method::GET,
"/lol/league-exp/v4/entries/{queue}/{tier}/{division}",
"league-exp-v4.getLeagueEntries",
),
(
Method::GET,
"/lol/league/v4/challengerleagues/by-queue/{queue}",
"league-v4.getChallengerLeague",
),
(
Method::GET,
"/lol/league/v4/entries/by-puuid/{encryptedPUUID}",
"league-v4.getLeagueEntriesByPUUID",
),
(
Method::GET,
"/lol/league/v4/entries/by-summoner/{encryptedSummonerId}",
"league-v4.getLeagueEntriesForSummoner",
),
(
Method::GET,
"/lol/league/v4/entries/{queue}/{tier}/{division}",
"league-v4.getLeagueEntries",
),
(
Method::GET,
"/lol/league/v4/grandmasterleagues/by-queue/{queue}",
"league-v4.getGrandmasterLeague",
),
(Method::GET, "/lol/league/v4/leagues/{leagueId}", "league-v4.getLeagueById"),
(
Method::GET,
"/lol/league/v4/masterleagues/by-queue/{queue}",
"league-v4.getMasterLeague",
),
(
Method::GET,
"/lol/challenges/v1/challenges/config",
"lol-challenges-v1.getAllChallengeConfigs",
),
(
Method::GET,
"/lol/challenges/v1/challenges/percentiles",
"lol-challenges-v1.getAllChallengePercentiles",
),
(
Method::GET,
"/lol/challenges/v1/challenges/{challengeId}/config",
"lol-challenges-v1.getChallengeConfigs",
),
(
Method::GET,
"/lol/challenges/v1/challenges/{challengeId}/leaderboards/by-level/{level}",
"lol-challenges-v1.getChallengeLeaderboards",
),
(
Method::GET,
"/lol/challenges/v1/challenges/{challengeId}/percentiles",
"lol-challenges-v1.getChallengePercentiles",
),
(
Method::GET,
"/lol/challenges/v1/player-data/{puuid}",
"lol-challenges-v1.getPlayerData",
),
(Method::GET, "/lol/rso-match/v1/matches/ids", "lol-rso-match-v1.getMatchIds"),
(Method::GET, "/lol/rso-match/v1/matches/{matchId}", "lol-rso-match-v1.getMatch"),
(
Method::GET,
"/lol/rso-match/v1/matches/{matchId}/timeline",
"lol-rso-match-v1.getTimeline",
),
(Method::GET, "/lol/status/v4/platform-data", "lol-status-v4.getPlatformData"),
(Method::GET, "/lor/deck/v1/decks/me", "lor-deck-v1.getDecks"),
(Method::POST, "/lor/deck/v1/decks/me", "lor-deck-v1.createDeck"),
(Method::GET, "/lor/inventory/v1/cards/me", "lor-inventory-v1.getCards"),
(
Method::GET,
"/lor/match/v1/matches/by-puuid/{puuid}/ids",
"lor-match-v1.getMatchIdsByPUUID",
),
(Method::GET, "/lor/match/v1/matches/{matchId}", "lor-match-v1.getMatch"),
(Method::GET, "/lor/ranked/v1/leaderboards", "lor-ranked-v1.getLeaderboards"),
(Method::GET, "/lor/status/v1/platform-data", "lor-status-v1.getPlatformData"),
(
Method::GET,
"/lol/match/v5/matches/by-puuid/{puuid}/ids",
"match-v5.getMatchIdsByPUUID",
),
(Method::GET, "/lol/match/v5/matches/{matchId}", "match-v5.getMatch"),
(Method::GET, "/lol/match/v5/matches/{matchId}/timeline", "match-v5.getTimeline"),
(
Method::GET,
"/lol/spectator/tft/v5/active-games/by-puuid/{encryptedPUUID}",
"spectator-tft-v5.getCurrentGameInfoByPuuid",
),
(
Method::GET,
"/lol/spectator/tft/v5/featured-games",
"spectator-tft-v5.getFeaturedGames",
),
(
Method::GET,
"/lol/spectator/v5/active-games/by-summoner/{encryptedPUUID}",
"spectator-v5.getCurrentGameInfoByPuuid",
),
(Method::GET, "/lol/spectator/v5/featured-games", "spectator-v5.getFeaturedGames"),
(
Method::GET,
"/fulfillment/v1/summoners/by-puuid/{rsoPUUID}",
"summoner-v4.getByRSOPUUID",
),
(
Method::GET,
"/lol/summoner/v4/summoners/by-account/{encryptedAccountId}",
"summoner-v4.getByAccountId",
),
(
Method::GET,
"/lol/summoner/v4/summoners/by-puuid/{encryptedPUUID}",
"summoner-v4.getByPUUID",
),
(Method::GET, "/lol/summoner/v4/summoners/me", "summoner-v4.getByAccessToken"),
(
Method::GET,
"/lol/summoner/v4/summoners/{encryptedSummonerId}",
"summoner-v4.getBySummonerId",
),
(Method::GET, "/tft/league/v1/challenger", "tft-league-v1.getChallengerLeague"),
(
Method::GET,
"/tft/league/v1/entries/by-summoner/{summonerId}",
"tft-league-v1.getLeagueEntriesForSummoner",
),
(
Method::GET,
"/tft/league/v1/entries/{tier}/{division}",
"tft-league-v1.getLeagueEntries",
),
(Method::GET, "/tft/league/v1/grandmaster", "tft-league-v1.getGrandmasterLeague"),
(Method::GET, "/tft/league/v1/leagues/{leagueId}", "tft-league-v1.getLeagueById"),
(Method::GET, "/tft/league/v1/master", "tft-league-v1.getMasterLeague"),
(
Method::GET,
"/tft/league/v1/rated-ladders/{queue}/top",
"tft-league-v1.getTopRatedLadder",
),
(
Method::GET,
"/tft/match/v1/matches/by-puuid/{puuid}/ids",
"tft-match-v1.getMatchIdsByPUUID",
),
(Method::GET, "/tft/match/v1/matches/{matchId}", "tft-match-v1.getMatch"),
(Method::GET, "/tft/status/v1/platform-data", "tft-status-v1.getPlatformData"),
(
Method::GET,
"/tft/summoner/v1/summoners/by-account/{encryptedAccountId}",
"tft-summoner-v1.getByAccountId",
),
(
Method::GET,
"/tft/summoner/v1/summoners/by-puuid/{encryptedPUUID}",
"tft-summoner-v1.getByPUUID",
),
(Method::GET, "/tft/summoner/v1/summoners/me", "tft-summoner-v1.getByAccessToken"),
(
Method::GET,
"/tft/summoner/v1/summoners/{encryptedSummonerId}",
"tft-summoner-v1.getBySummonerId",
),
(
Method::POST,
"/lol/tournament-stub/v5/codes",
"tournament-stub-v5.createTournamentCode",
),
(
Method::GET,
"/lol/tournament-stub/v5/codes/{tournamentCode}",
"tournament-stub-v5.getTournamentCode",
),
(
Method::GET,
"/lol/tournament-stub/v5/lobby-events/by-code/{tournamentCode}",
"tournament-stub-v5.getLobbyEventsByCode",
),
(
Method::POST,
"/lol/tournament-stub/v5/providers",
"tournament-stub-v5.registerProviderData",
),
(
Method::POST,
"/lol/tournament-stub/v5/tournaments",
"tournament-stub-v5.registerTournament",
),
(Method::POST, "/lol/tournament/v5/codes", "tournament-v5.createTournamentCode"),
(
Method::GET,
"/lol/tournament/v5/codes/{tournamentCode}",
"tournament-v5.getTournamentCode",
),
(
Method::PUT,
"/lol/tournament/v5/codes/{tournamentCode}",
"tournament-v5.updateCode",
),
(
Method::GET,
"/lol/tournament/v5/games/by-code/{tournamentCode}",
"tournament-v5.getGames",
),
(
Method::GET,
"/lol/tournament/v5/lobby-events/by-code/{tournamentCode}",
"tournament-v5.getLobbyEventsByCode",
),
(Method::POST, "/lol/tournament/v5/providers", "tournament-v5.registerProviderData"),
(Method::POST, "/lol/tournament/v5/tournaments", "tournament-v5.registerTournament"),
(
Method::GET,
"/val/match/console/v1/matches/{matchId}",
"val-console-match-v1.getMatch",
),
(
Method::GET,
"/val/match/console/v1/matchlists/by-puuid/{puuid}",
"val-console-match-v1.getMatchlist",
),
(
Method::GET,
"/val/match/console/v1/recent-matches/by-queue/{queue}",
"val-console-match-v1.getRecent",
),
(
Method::GET,
"/val/console/ranked/v1/leaderboards/by-act/{actId}",
"val-console-ranked-v1.getLeaderboard",
),
(Method::GET, "/val/content/v1/contents", "val-content-v1.getContent"),
(Method::GET, "/val/match/v1/matches/{matchId}", "val-match-v1.getMatch"),
(
Method::GET,
"/val/match/v1/matchlists/by-puuid/{puuid}",
"val-match-v1.getMatchlist",
),
(
Method::GET,
"/val/match/v1/recent-matches/by-queue/{queue}",
"val-match-v1.getRecent",
),
(
Method::GET,
"/val/ranked/v1/leaderboards/by-act/{actId}",
"val-ranked-v1.getLeaderboard",
),
(Method::GET, "/val/status/v1/platform-data", "val-status-v1.getPlatformData"),
];

View file

@ -1,107 +1,3 @@
#![cfg_attr(any(), rustfmt::skip)]
///////////////////////////////////////////////
// //
// ! //
// This file is automatically generated! //
// Do not directly edit! //
// //
///////////////////////////////////////////////
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version 996d171a2b79e9bb85c549f47b07c6ef2721fc8a
//! Metadata about the Riot API and Riven.
//!
//! Note: this modules is automatically generated.
/// Metadata for endpoints. Each tuple corresponds to one endpoint and contains
/// the HTTP [`Method`](reqwest::Method), `str` path, and the method's `str` ID.
pub static ALL_ENDPOINTS: [(reqwest::Method, &str, &str); 87] = [
(reqwest::Method::GET, "/riot/account/v1/accounts/by-puuid/{puuid}", "account-v1.getByPuuid"),
(reqwest::Method::GET, "/riot/account/v1/accounts/by-riot-id/{gameName}/{tagLine}", "account-v1.getByRiotId"),
(reqwest::Method::GET, "/riot/account/v1/accounts/me", "account-v1.getByAccessToken"),
(reqwest::Method::GET, "/riot/account/v1/active-shards/by-game/{game}/by-puuid/{puuid}", "account-v1.getActiveShard"),
(reqwest::Method::GET, "/lol/champion-mastery/v4/champion-masteries/by-puuid/{encryptedPUUID}", "champion-mastery-v4.getAllChampionMasteriesByPUUID"),
(reqwest::Method::GET, "/lol/champion-mastery/v4/champion-masteries/by-puuid/{encryptedPUUID}/by-champion/{championId}", "champion-mastery-v4.getChampionMasteryByPUUID"),
(reqwest::Method::GET, "/lol/champion-mastery/v4/champion-masteries/by-puuid/{encryptedPUUID}/top", "champion-mastery-v4.getTopChampionMasteriesByPUUID"),
(reqwest::Method::GET, "/lol/champion-mastery/v4/scores/by-puuid/{encryptedPUUID}", "champion-mastery-v4.getChampionMasteryScoreByPUUID"),
(reqwest::Method::GET, "/lol/platform/v3/champion-rotations", "champion-v3.getChampionInfo"),
(reqwest::Method::GET, "/lol/clash/v1/players/by-puuid/{puuid}", "clash-v1.getPlayersByPUUID"),
(reqwest::Method::GET, "/lol/clash/v1/teams/{teamId}", "clash-v1.getTeamById"),
(reqwest::Method::GET, "/lol/clash/v1/tournaments", "clash-v1.getTournaments"),
(reqwest::Method::GET, "/lol/clash/v1/tournaments/by-team/{teamId}", "clash-v1.getTournamentByTeam"),
(reqwest::Method::GET, "/lol/clash/v1/tournaments/{tournamentId}", "clash-v1.getTournamentById"),
(reqwest::Method::GET, "/lol/league-exp/v4/entries/{queue}/{tier}/{division}", "league-exp-v4.getLeagueEntries"),
(reqwest::Method::GET, "/lol/league/v4/challengerleagues/by-queue/{queue}", "league-v4.getChallengerLeague"),
(reqwest::Method::GET, "/lol/league/v4/entries/by-puuid/{encryptedPUUID}", "league-v4.getLeagueEntriesByPUUID"),
(reqwest::Method::GET, "/lol/league/v4/entries/by-summoner/{encryptedSummonerId}", "league-v4.getLeagueEntriesForSummoner"),
(reqwest::Method::GET, "/lol/league/v4/entries/{queue}/{tier}/{division}", "league-v4.getLeagueEntries"),
(reqwest::Method::GET, "/lol/league/v4/grandmasterleagues/by-queue/{queue}", "league-v4.getGrandmasterLeague"),
(reqwest::Method::GET, "/lol/league/v4/leagues/{leagueId}", "league-v4.getLeagueById"),
(reqwest::Method::GET, "/lol/league/v4/masterleagues/by-queue/{queue}", "league-v4.getMasterLeague"),
(reqwest::Method::GET, "/lol/challenges/v1/challenges/config", "lol-challenges-v1.getAllChallengeConfigs"),
(reqwest::Method::GET, "/lol/challenges/v1/challenges/percentiles", "lol-challenges-v1.getAllChallengePercentiles"),
(reqwest::Method::GET, "/lol/challenges/v1/challenges/{challengeId}/config", "lol-challenges-v1.getChallengeConfigs"),
(reqwest::Method::GET, "/lol/challenges/v1/challenges/{challengeId}/leaderboards/by-level/{level}", "lol-challenges-v1.getChallengeLeaderboards"),
(reqwest::Method::GET, "/lol/challenges/v1/challenges/{challengeId}/percentiles", "lol-challenges-v1.getChallengePercentiles"),
(reqwest::Method::GET, "/lol/challenges/v1/player-data/{puuid}", "lol-challenges-v1.getPlayerData"),
(reqwest::Method::GET, "/lol/rso-match/v1/matches/ids", "lol-rso-match-v1.getMatchIds"),
(reqwest::Method::GET, "/lol/rso-match/v1/matches/{matchId}", "lol-rso-match-v1.getMatch"),
(reqwest::Method::GET, "/lol/rso-match/v1/matches/{matchId}/timeline", "lol-rso-match-v1.getTimeline"),
(reqwest::Method::GET, "/lol/status/v4/platform-data", "lol-status-v4.getPlatformData"),
(reqwest::Method::GET, "/lor/deck/v1/decks/me", "lor-deck-v1.getDecks"),
(reqwest::Method::POST, "/lor/deck/v1/decks/me", "lor-deck-v1.createDeck"),
(reqwest::Method::GET, "/lor/inventory/v1/cards/me", "lor-inventory-v1.getCards"),
(reqwest::Method::GET, "/lor/match/v1/matches/by-puuid/{puuid}/ids", "lor-match-v1.getMatchIdsByPUUID"),
(reqwest::Method::GET, "/lor/match/v1/matches/{matchId}", "lor-match-v1.getMatch"),
(reqwest::Method::GET, "/lor/ranked/v1/leaderboards", "lor-ranked-v1.getLeaderboards"),
(reqwest::Method::GET, "/lor/status/v1/platform-data", "lor-status-v1.getPlatformData"),
(reqwest::Method::GET, "/lol/match/v5/matches/by-puuid/{puuid}/ids", "match-v5.getMatchIdsByPUUID"),
(reqwest::Method::GET, "/lol/match/v5/matches/{matchId}", "match-v5.getMatch"),
(reqwest::Method::GET, "/lol/match/v5/matches/{matchId}/timeline", "match-v5.getTimeline"),
(reqwest::Method::GET, "/lol/spectator/tft/v5/active-games/by-puuid/{encryptedPUUID}", "spectator-tft-v5.getCurrentGameInfoByPuuid"),
(reqwest::Method::GET, "/lol/spectator/tft/v5/featured-games", "spectator-tft-v5.getFeaturedGames"),
(reqwest::Method::GET, "/lol/spectator/v5/active-games/by-summoner/{encryptedPUUID}", "spectator-v5.getCurrentGameInfoByPuuid"),
(reqwest::Method::GET, "/lol/spectator/v5/featured-games", "spectator-v5.getFeaturedGames"),
(reqwest::Method::GET, "/fulfillment/v1/summoners/by-puuid/{rsoPUUID}", "summoner-v4.getByRSOPUUID"),
(reqwest::Method::GET, "/lol/summoner/v4/summoners/by-account/{encryptedAccountId}", "summoner-v4.getByAccountId"),
(reqwest::Method::GET, "/lol/summoner/v4/summoners/by-puuid/{encryptedPUUID}", "summoner-v4.getByPUUID"),
(reqwest::Method::GET, "/lol/summoner/v4/summoners/me", "summoner-v4.getByAccessToken"),
(reqwest::Method::GET, "/lol/summoner/v4/summoners/{encryptedSummonerId}", "summoner-v4.getBySummonerId"),
(reqwest::Method::GET, "/tft/league/v1/challenger", "tft-league-v1.getChallengerLeague"),
(reqwest::Method::GET, "/tft/league/v1/entries/by-summoner/{summonerId}", "tft-league-v1.getLeagueEntriesForSummoner"),
(reqwest::Method::GET, "/tft/league/v1/entries/{tier}/{division}", "tft-league-v1.getLeagueEntries"),
(reqwest::Method::GET, "/tft/league/v1/grandmaster", "tft-league-v1.getGrandmasterLeague"),
(reqwest::Method::GET, "/tft/league/v1/leagues/{leagueId}", "tft-league-v1.getLeagueById"),
(reqwest::Method::GET, "/tft/league/v1/master", "tft-league-v1.getMasterLeague"),
(reqwest::Method::GET, "/tft/league/v1/rated-ladders/{queue}/top", "tft-league-v1.getTopRatedLadder"),
(reqwest::Method::GET, "/tft/match/v1/matches/by-puuid/{puuid}/ids", "tft-match-v1.getMatchIdsByPUUID"),
(reqwest::Method::GET, "/tft/match/v1/matches/{matchId}", "tft-match-v1.getMatch"),
(reqwest::Method::GET, "/tft/status/v1/platform-data", "tft-status-v1.getPlatformData"),
(reqwest::Method::GET, "/tft/summoner/v1/summoners/by-account/{encryptedAccountId}", "tft-summoner-v1.getByAccountId"),
(reqwest::Method::GET, "/tft/summoner/v1/summoners/by-puuid/{encryptedPUUID}", "tft-summoner-v1.getByPUUID"),
(reqwest::Method::GET, "/tft/summoner/v1/summoners/me", "tft-summoner-v1.getByAccessToken"),
(reqwest::Method::GET, "/tft/summoner/v1/summoners/{encryptedSummonerId}", "tft-summoner-v1.getBySummonerId"),
(reqwest::Method::POST, "/lol/tournament-stub/v5/codes", "tournament-stub-v5.createTournamentCode"),
(reqwest::Method::GET, "/lol/tournament-stub/v5/codes/{tournamentCode}", "tournament-stub-v5.getTournamentCode"),
(reqwest::Method::GET, "/lol/tournament-stub/v5/lobby-events/by-code/{tournamentCode}", "tournament-stub-v5.getLobbyEventsByCode"),
(reqwest::Method::POST, "/lol/tournament-stub/v5/providers", "tournament-stub-v5.registerProviderData"),
(reqwest::Method::POST, "/lol/tournament-stub/v5/tournaments", "tournament-stub-v5.registerTournament"),
(reqwest::Method::POST, "/lol/tournament/v5/codes", "tournament-v5.createTournamentCode"),
(reqwest::Method::GET, "/lol/tournament/v5/codes/{tournamentCode}", "tournament-v5.getTournamentCode"),
(reqwest::Method::PUT, "/lol/tournament/v5/codes/{tournamentCode}", "tournament-v5.updateCode"),
(reqwest::Method::GET, "/lol/tournament/v5/games/by-code/{tournamentCode}", "tournament-v5.getGames"),
(reqwest::Method::GET, "/lol/tournament/v5/lobby-events/by-code/{tournamentCode}", "tournament-v5.getLobbyEventsByCode"),
(reqwest::Method::POST, "/lol/tournament/v5/providers", "tournament-v5.registerProviderData"),
(reqwest::Method::POST, "/lol/tournament/v5/tournaments", "tournament-v5.registerTournament"),
(reqwest::Method::GET, "/val/match/console/v1/matches/{matchId}", "val-console-match-v1.getMatch"),
(reqwest::Method::GET, "/val/match/console/v1/matchlists/by-puuid/{puuid}", "val-console-match-v1.getMatchlist"),
(reqwest::Method::GET, "/val/match/console/v1/recent-matches/by-queue/{queue}", "val-console-match-v1.getRecent"),
(reqwest::Method::GET, "/val/console/ranked/v1/leaderboards/by-act/{actId}", "val-console-ranked-v1.getLeaderboard"),
(reqwest::Method::GET, "/val/content/v1/contents", "val-content-v1.getContent"),
(reqwest::Method::GET, "/val/match/v1/matches/{matchId}", "val-match-v1.getMatch"),
(reqwest::Method::GET, "/val/match/v1/matchlists/by-puuid/{puuid}", "val-match-v1.getMatchlist"),
(reqwest::Method::GET, "/val/match/v1/recent-matches/by-queue/{queue}", "val-match-v1.getRecent"),
(reqwest::Method::GET, "/val/ranked/v1/leaderboards/by-act/{actId}", "val-ranked-v1.getLeaderboard"),
(reqwest::Method::GET, "/val/status/v1/platform-data", "val-status-v1.getPlatformData"),
];
include_autogen!("meta.gen.rs");

5995
riven/src/models.gen.rs Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,2 +0,0 @@
node_modules/
.*.json

View file

@ -1,168 +0,0 @@
{{
const dotUtils = require('./dotUtils.js');
const champions = require('./.champion.json')
.filter(({ id }) => id > 0)
/* Ignore strawberry champions for now */
.filter(({ alias }) => !alias.startsWith('Strawberry_'))
.sortBy(({ name }) => name);
const constName = name => dotUtils.changeCase.constantCase(name).replace(/[^_A-Z0-9]+/g, '');
const constNamePad = 12;
}}{{= dotUtils.preamble() }}
newtype_enum! {
/// A League of Legends champion.
///
/// This newtype acts as a C-like enum; each variant corresponds to an
/// integer value. Using a newtype allows _unknown_ variants to be
/// represented. This is important when Riot adds new champions.
///
/// Field | Name | Identifier | Id
/// ---|---|---|---
/// `NONE` | None (no ban) | | -1
{{
for (const { id, alias, name } of champions) {
}}
/// `{{= constName(name) }}` | "{{= name }}" | "{{= alias }}" | {{= id }}
{{
}
}}
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) {
}}
/// `{{= id }}`.
{{= constName(name) }} = {{= id }},
{{
}
}}
}
}
impl Champion {
/// The champion's name (`en_US` localization).
pub const fn name(self) -> Option<&'static str> {
match self {
{{
for (const { name } of champions) {
}}
Self::{{= constName(name).padEnd(constNamePad) }} => Some("{{= name }}"),
{{
}
}}
_ => None,
}
}
/// The champion's identifier key. Somtimes called "key", "identifier", or "alias".
/// This is mainly used in DDragon paths.
///
/// This is generally the `en_US` name with spaces and punctuation removed,
/// capitalization preserved, however the follow are exceptions:
///
/// Field | Name | Identifier | Id
/// ---|---|---|---
{{
for (const { id, alias, name } of champions) {
if (name.replace(/[^a-zA-Z0-9]+/, '') !== alias) {
}}
/// `{{= constName(name) }}` | "{{= name }}" | "{{= alias }}" | {{= id }}
{{
}
}
}}
pub const fn identifier(self) -> Option<&'static str> {
match self {
{{
for (const { name, alias } of champions) {
}}
Self::{{= constName(name).padEnd(constNamePad) }} => Some("{{= alias }}"),
{{
}
}}
_ => None,
}
}
/// https://github.com/MingweiSamuel/Riven/issues/36
pub(crate) fn serialize_result<S>(
val: &Result<Self, std::num::TryFromIntError>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
use serde::ser::Serialize;
val.unwrap_or(Champion(-1)).serialize(serializer)
}
/// https://github.com/MingweiSamuel/Riven/issues/36
pub(crate) fn deserialize_result<'de, D>(
deserializer: D,
) -> Result<Result<Self, std::num::TryFromIntError>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
use std::convert::TryInto;
<i64 as serde::de::Deserialize>::deserialize(deserializer).map(|id| id.try_into().map(Self))
}
}
/// The error used for failures in [`Champion`]'s
/// [`FromStr`](std::str::FromStr) implementation.
///
/// Currently only internally stores the four characters used to parse the
/// champion, but may change in the future.
#[derive(Debug)]
pub struct ParseChampionError([char; 4]);
impl std::fmt::Display for ParseChampionError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let s: String = self.0.iter().copied().take_while(|&c| '\0' != c).collect();
write!(f, "Failed to parse unknown champion prefix: {:?}", s)
}
}
impl std::error::Error for ParseChampionError {}
impl std::str::FromStr for Champion {
type Err = ParseChampionError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut chars = ['\0'; 4];
s.chars()
.take(4)
.filter(|c| c.is_ascii_alphanumeric())
.map(|c| c.to_ascii_uppercase())
.enumerate()
.for_each(|(i, c)| chars[i] = c);
match chars {
{{
const keyStrings = (name, alias) => new Set([].concat(...[ name, alias ].map(s => s.toUpperCase())
.map(s => [
s.replace(/[^A-Z0-9]+/, '').substring(0, 4),
s.split(/[^A-Z0-9]/, 1)[0].substring(0, 4),
s.split(/[^A-Z]/, 1)[0].substring(0, 4),
])));
for (const { id, alias, name } of champions) {
for (const prefix of keyStrings(name, alias)) {
const chars = Object.assign(Array(4).fill('\\0'), Array.from(prefix))
.map(c => `'${c}'`)
.map(c => c.padStart(4));
}}
/* {{= prefix.padEnd(4) }} */ [{{= chars.join(', ') }}] => Ok(Champion::{{= constName(name) }}),
{{
}
}
}}
unknown => Err(ParseChampionError(unknown)),
}
}
}
impl std::convert::TryFrom<&str> for Champion {
type Error = <Self as std::str::FromStr>::Err;
fn try_from(value: &str) -> Result<Self, Self::Error> {
<Self as std::str::FromStr>::from_str(value)
}
}

View file

@ -1,33 +0,0 @@
{{
const dotUtils = require('./dotUtils.js');
const gameModes = require('./.gameModes.json');
}}{{= dotUtils.preamble() }}
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, EnumVariantNames, IntoStaticStr)]
#[repr(u8)]
pub enum GameMode {
/// Catch-all variant for new, unknown game modes.
#[strum(default)]
UNKNOWN(String),
{{
for (const e of gameModes) {
const desc = e['x-desc'] ? e['x-desc'].split('\n') : [];
}}
{{~ desc :line }}
/// {{= line }}
{{~}}
{{= e['x-name'] }},
{{
}
}}
}
serde_strum_unknown!(GameMode);

View file

@ -1,32 +0,0 @@
{{
const dotUtils = require('./dotUtils.js');
const gameTypes = require('./.gameTypes.json');
}}{{= dotUtils.preamble() }}
use strum_macros::{ EnumString, Display, AsRefStr, IntoStaticStr };
/// League of Legends game type: matched game, custom game, or tutorial game.
#[derive(Debug, Copy, Clone)]
#[derive(Eq, PartialEq, Hash)]
#[derive(EnumString, Display, AsRefStr, IntoStaticStr)]
#[derive(serde::Serialize, crate::de::Deserialize)]
#[repr(u8)]
pub enum GameType {
{{
for (const e of gameTypes) {
const desc = e['x-desc'] ? e['x-desc'].split('\n') : [];
const nameNoGame = e['x-name'].replace(/_GAME$/, "");
}}
{{~ desc :line }}
/// {{= line }}
{{~}}
#[strum(to_string = "{{= e['x-name'] }}", serialize = "{{= nameNoGame }}")]
#[serde(alias = "{{= nameNoGame }}")]
{{= e['x-name'] }},
{{
}
}}
}
#[cfg(test)]
mod test;

View file

@ -1,22 +0,0 @@
{{
const dotUtils = require('./dotUtils.js');
const maps = require('./.maps.json');
}}{{= dotUtils.preamble() }}
newtype_enum! {
/// A League of Legends map.
pub newtype_enum Map(u8) {
{{
for (const e of maps) {
const desc = e['x-desc'] ? e['x-desc'].split('\n') : [];
}}
/// `{{= e['x-value'] }}`.
{{~ desc :line }}
/// {{= line }}
{{~}}
{{= e['x-name'] }} = {{= e['x-value'] }},
{{
}
}}
}
}

View file

@ -1,29 +0,0 @@
{{
const dotUtils = require('./dotUtils.js');
const queues = require('./.queues.json');
}}{{= dotUtils.preamble() }}
newtype_enum! {
/// A League of Legends matchmaking queue.
pub newtype_enum Queue(u16) {
{{
for (const e of queues) {
const desc = e['x-desc'] ? e['x-desc'].split('\n') : [];
}}
/// `{{= e['x-value'] }}`.
{{~ desc :line }}
/// {{= line }}
{{~}}
{{? e.notes }}
///
/// {{= e.notes }}
{{?}}
{{? e['x-deprecated'] }}
#[deprecated(note="{{= e.notes }}")]
{{?}}
{{= e['x-name'] }} = {{= e['x-value'] }},
{{
}
}}
}
}

View file

@ -1,39 +0,0 @@
{{
const dotUtils = require('./dotUtils.js');
const queueTypes = require('./.queueTypes.json');
}}{{= dotUtils.preamble() }}
use strum_macros::{ EnumString, EnumVariantNames, IntoStaticStr };
/// LoL or TFT ranked queue types.
#[non_exhaustive]
#[derive(Debug, Clone)]
#[derive(Eq, PartialEq, Hash)]
#[derive(EnumString, EnumVariantNames, IntoStaticStr)]
#[repr(u8)]
pub enum QueueType {
/// Catch-all variant for new, unknown queue types.
#[strum(default)]
UNKNOWN(String),
{{
for (const e of queueTypes) {
const desc = e['x-desc'] ? e['x-desc'].split('\n') : [];
}}
{{~ desc :line }}
/// {{= line }}
{{~}}
{{? e['x-deprecated'] }}
/// {{= e.notes }}
#[deprecated(note="{{= e.notes }}")]
{{?}}
{{= e['x-name'] }},
{{
}
}}
}
serde_strum_unknown!(QueueType);
#[cfg(test)]
mod test;

View file

@ -1,195 +0,0 @@
{{
const dotUtils = require('./dotUtils.js');
const routesTable = require('./.routesTable.json');
}}{{= dotUtils.preamble() }}
#![allow(clippy::upper_case_acronyms)]
use num_enum::{ IntoPrimitive, TryFromPrimitive };
use strum_macros::{ EnumString, EnumIter, Display, IntoStaticStr };
/// Regional routes, used in tournament services, Legends of Runeterra (LoR), and other some endpoints.
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[derive(Clone, Copy)]
#[repr(u8)]
#[non_exhaustive]
pub enum RegionalRoute {
{{
for (const [ name, { id, description, deprecated } ] of Object.entries(routesTable['regional'])) {
const desc = description.split('\n');
}}
{{~ desc :line }}
/// {{= line }}
{{~}}
///
/// `{{= id }}` (riotapi-schema ID/repr)
{{? deprecated }}
#[deprecated]
{{?}}
{{= name.toUpperCase() }} = {{= id }},
{{
}
}}
}
/// Platform routes for League of Legends (LoL), Teamfight Tactics (TFT), and Legends of Runeterra (LoR).
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[derive(Clone, Copy)]
#[repr(u8)]
#[non_exhaustive]
// Note: strum(serialize = ...) actually specifies extra DEserialization values.
pub enum PlatformRoute {
{{
for (const [ name, { id, description, altName, deprecated } ] of Object.entries(routesTable['platform'])) {
const desc = description.split('\n');
}}
{{~ desc :line }}
/// {{= line }}
{{~}}
///
/// `{{= id }}` (riotapi-schema ID/repr)
{{? deprecated }}
#[deprecated]
{{?}}
{{? altName }}
#[strum(to_string="{{= name.toUpperCase() }}", serialize="{{= altName }}")]
{{?}}
{{= name.toUpperCase() }} = {{= id }},
{{
}
}}
}
impl PlatformRoute {
/// Converts this [`PlatformRoute`] into its corresponding
/// [`RegionalRoute`] for LoL and TFT match endpoints.
/// For example, [`match-v5`](crate::endpoints::MatchV5).
pub fn to_regional(self) -> RegionalRoute {
match self {
{{
for (const [ name, { regionalRoute } ] of Object.entries(routesTable['platform'])) {
}}
Self::{{= name.toUpperCase() }} => RegionalRoute::{{= regionalRoute.toUpperCase() }},
{{
}
}}
}
}
/// Converts this [`PlatformRoute`] into its corresponding
/// [`RegionalRoute`] for LoR endpoints.
/// For example, [`lor-match-v1`](crate::endpoints::LorMatchV1).
pub fn to_regional_lor(self) -> RegionalRoute {
match self {
{{
for (const [ name, { regionalRouteLor } ] of Object.entries(routesTable['platform'])) {
}}
Self::{{= name.toUpperCase() }} => RegionalRoute::{{= regionalRouteLor.toUpperCase() }},
{{
}
}}
}
}
/// Used in the LoL Tournament API. Specifically
/// [`TournamentStubV5`](crate::endpoints::TournamentStubV5)/[`TournamentV5`](crate::endpoints::TournamentV5).
pub fn to_tournament_region(self) -> Option<TournamentRegion> {
match self {
{{
for (const [ name, { tournamentRegion } ] of Object.entries(routesTable['platform'])) {
if (!tournamentRegion) continue;
}}
Self::{{= name.toUpperCase() }} => Some(TournamentRegion::{{= tournamentRegion }}),
{{
}
}}
_other => None,
}
}
/// Get the slightly more human-friendly alternate name for this `PlatformRoute`. Specifically
/// excludes any trailing numbers and appends extra N(orth), S(outh), E(ast), and/or W(est)
/// suffixes to some names. Some of these are old region names which are often still used as
/// user-facing names, e.g. on op.gg.
///
/// Note these strings *are* handled by the `FromStr` implementation, if you wish to parse them
/// back into `PlatformRoute`s.
pub fn as_region_str(self) -> &'static str {
match self {
{{
for (const [ name, { altName } ] of Object.entries(routesTable['platform'])) {
if (!altName) continue;
}}
Self::{{= name.toUpperCase() }} => "{{= altName }}",
{{
}
}}
other => other.into(),
}
}
}
/// Platform routes for Valorant.
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[derive(Clone, Copy)]
#[repr(u8)]
#[non_exhaustive]
pub enum ValPlatformRoute {
{{
for (const [ name, { id, description, deprecated } ] of Object.entries(routesTable['val-platform'])) {
const desc = description.split('\n');
}}
{{~ desc :line }}
/// {{= line }}
{{~}}
///
/// `{{= id }}` (riotapi-schema ID/repr)
{{? deprecated }}
#[deprecated]
{{?}}
{{= name.toUpperCase() }} = {{= id }},
{{
}
}}
}
/// Tournament regions for League of Legends (LoL) used in
/// [`TournamentStubV5`](crate::endpoints::TournamentStubV5)/[`TournamentV5`](crate::endpoints::TournamentV5).
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(EnumString, EnumIter, Display, IntoStaticStr)]
#[derive(serde::Serialize, crate::de::Deserialize)]
#[derive(Clone, Copy)]
#[repr(u8)]
#[non_exhaustive]
// Note: strum(serialize = ...) actually specifies extra DEserialization values.
pub enum TournamentRegion {
{{
for (const [ name, { id, description, tournamentRegion, deprecated } ] of Object.entries(routesTable['platform'])) {
if (tournamentRegion) {
const desc = description.split('\n');
}}
{{~ desc :line }}
/// {{= line }}
{{~}}
{{? deprecated }}
#[deprecated]
{{?}}
{{= tournamentRegion }} = {{= id }},
{{
}
}
}}
}

View file

@ -1,22 +0,0 @@
{{
const dotUtils = require('./dotUtils.js');
const seasons = require('./.seasons.json');
}}{{= dotUtils.preamble() }}
newtype_enum! {
/// A League of Legends season for competitive matchmaking.
pub newtype_enum Season(u8) {
{{
for (const e of seasons) {
const desc = e['x-desc'] ? e['x-desc'].split('\n') : [];
}}
/// `{{= e['x-value'] }}`.
{{~ desc :line }}
/// {{= line }}
{{~}}
{{= e['x-name'] }} = {{= e['x-value'] }},
{{
}
}}
}
}

View file

@ -1,168 +0,0 @@
const changeCase = require('change-case');
// flatMap: https://gist.github.com/samgiles/762ee337dff48623e729
// [B](f: (A) ⇒ [B]): [B] ; Although the types in the arrays aren't strict (:
Array.prototype.flatMap = function(lambda) {
return Array.prototype.concat.apply([], this.map(lambda));
};
Array.prototype.groupBy = function(lambda) {
return Object.entries(this.reduce((agg, x) => {
const k = lambda(x);
(agg[k] = agg[k] || []).push(x);
return agg;
}, {}));
};
Array.prototype.sortBy = function(lambda) {
return this.sort((a, b) => {
const va = lambda(a);
const vb = lambda(b);
if ((typeof va) !== (typeof vb))
throw Error(`Mismatched sort types: ${typeof va}, ${typeof vb}.`);
if (typeof va === 'number')
return va - vb;
if (typeof va === 'string')
return va.localeCompare(vb);
throw Error(`Unknown sort type: ${typeof va}.`);
});
};
function preamble() {
return `\
#![cfg_attr(any(), rustfmt::skip)]
///////////////////////////////////////////////
// //
// ! //
// This file is automatically generated! //
// Do not directly edit! //
// //
///////////////////////////////////////////////`;
}
function capitalize(input) {
return input[0].toUpperCase() + input.slice(1);
}
function decapitalize(input) {
return input[0].toLowerCase() + input.slice(1);
}
function normalizeSchemaName(name) {
return name.replace(/DTO/ig, '');
}
function normalizeArgName(name) {
const tokens = name.split('_');
const argName = decapitalize(tokens.map(capitalize).join(''));
return 'base' === argName ? 'Base' : argName;
}
function normalizePropName(propName) {
let out = changeCase.snakeCase(propName);
if (/^\d/.test(out)) // No leading digits.
out = 'x' + out;
if ('type' === out)
return 'r#' + out;
return out;
}
function stringifyType(prop, { optional = false, fullpath = true, owned = true }) {
if (prop.anyOf) {
prop = prop.anyOf[0];
}
if (optional) {
return `Option<${stringifyType(prop, { fullpath, owned })}>`;
}
let enumType = prop['x-enum'];
if (enumType && 'locale' !== enumType)
return 'crate::consts::' + changeCase.pascalCase(enumType);
let refType = prop['$ref'];
if (refType) {
let [endpoint, schema] = refType.slice(refType.lastIndexOf('/') + 1).split('.');
return 'crate::models::' + changeCase.snakeCase(endpoint) + '::' + normalizeSchemaName(schema);
}
switch (prop.type) {
case 'boolean': return 'bool';
case 'integer': return ('int32' === prop.format ? 'i32' : 'i64');
case 'number': return ('float' === prop.format ? 'f32' : 'f64');
case 'array':
const subprop = stringifyType(prop.items, { optional, fullpath, owned });
return (owned ? (fullpath ? 'std::vec::' : '') + `Vec<${subprop}>` : `&[${subprop}]`);
case 'string': return (owned ? 'String' : '&str');
case 'object':
if (1 === Object.keys(prop).length) { // Only `{ "type": "object" }`.
return 'serde_json::Map<String, serde_json::Value>'
}
return 'std::collections::HashMap<' + stringifyType(prop['x-key'], { optional, fullpath, owned }) + ', ' +
stringifyType(prop.additionalProperties, { optional, fullpath, owned }) + '>';
default: return prop.type;
}
}
function formatJsonProperty(name, prop) {
const alias = prop['x-alias'];
if (alias)
return `#[serde(rename = ${JSON.stringify(name)}, alias = ${JSON.stringify(alias)})]`;
else
return `#[serde(rename = ${JSON.stringify(name)})]`;
}
function formatAddQueryParam(param) {
const k = `"${param.name}"`;
const name = normalizePropName(param.name);
const condStart = param.required ? '' : `if let Some(${name}) = ${name} { `;
const condEnd = param.required ? '' : ' } else { request }'
const prop = param.schema;
switch (prop.type) {
case 'array': return `let request = ${condStart}request.query(&*${name}.iter()`
+ `.map(|w| ( ${k}, w )).collect::<Vec<_>>())${condEnd};`;
case 'object':
throw 'unsupported';
default:
return `let request = ${condStart}request.query(&[ (${k}, ${name}) ])${condEnd};`;
}
}
function formatAddHeaderParam(param) {
const k = `"${param.name}"`;
const name = changeCase.snakeCase(param.name);
const condStart = param.required ? '' : `mut request = request; if let Some(${name}) = ${name} { `;
const condEnd = param.required ? '' : ' }'
const prop = param.schema;
switch (prop.type) {
case 'string':
return `let ${condStart}request = request.header(${k}, ${name});${condEnd}`;
case 'object':
throw 'unsupported';
default:
return `let ${condStart}request = request.header(${k}, ${name}.to_string());${condEnd}`;
}
}
function formatRouteArgument(route, pathParams = []) {
if (!pathParams.length)
return `"${route}"`;
route = route.replace(/\{\S+?\}/g, '{}');
const args = pathParams
.map(({name}) => name)
.map(changeCase.snakeCase)
.join(', ');
return `&format!("${route}", ${args})`;
}
module.exports = {
changeCase,
preamble,
capitalize,
decapitalize,
normalizeSchemaName,
normalizeArgName,
normalizePropName,
stringifyType,
formatJsonProperty,
formatAddQueryParam,
formatAddHeaderParam,
formatRouteArgument,
};

View file

@ -1,219 +0,0 @@
{{
const spec = require('./.spec.json');
const dotUtils = require('./dotUtils.js');
}}{{= dotUtils.preamble() }}
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version {{= spec.info.version }}
//! Automatically generated endpoint handles.
#![allow(clippy::let_and_return, clippy::too_many_arguments)]
use std::future::Future;
use std::vec::Vec;
#[cfg(feature="metrics")]
use crate::metrics;
#[cfg(feature="tracing")]
use tracing::Instrument;
use reqwest::Method;
use crate::Result;
use crate::consts::{ RegionalRoute, PlatformRoute, ValPlatformRoute };
use crate::riot_api::RiotApi;
{{
const endpointGroups = {};
for (let path of Object.entries(spec.paths)) {
let ep = path[1]['x-endpoint'];
endpointGroups[ep] = endpointGroups[ep] || [];
endpointGroups[ep].push(path);
}
}}
impl RiotApi {
{{
for (const endpointName of Object.keys(endpointGroups)) {
const method = dotUtils.changeCase.snakeCase(endpointName);
const type = dotUtils.changeCase.pascalCase(endpointName);
}}
/// Returns a handle for accessing [{{= type }}](crate::endpoints::{{= type }}) endpoints.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/apis#{{= endpointName }}" target="_blank">`{{= endpointName }}`</a>
///
/// Note: this method is automatically generated.
#[inline]
pub fn {{= method }}(&self) -> {{= type }} {
{{= type }} { base: self }
}
{{
}
}}
}
{{
for (let [ endpointName, endpointMethods ] of Object.entries(endpointGroups))
{
let endpoint = dotUtils.changeCase.pascalCase(endpointName);
const endpoint_snake_case = dotUtils.changeCase.snakeCase(endpointName);
}}
/// {{= endpoint }} endpoints handle, accessed by calling [`{{= endpoint_snake_case }}()`](RiotApi::{{= endpoint_snake_case }}) on a [`RiotApi`] instance.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/apis#{{= endpointName }}" target="_blank">`{{= endpointName }}`</a>
///
/// Note: this struct is automatically generated.
#[repr(transparent)]
pub struct {{= endpoint }}<'a> {
base: &'a RiotApi,
}
impl<'a> {{= endpoint }}<'a> {
{{
for (const [ route, path ] of endpointMethods)
{
for (const [ verb, operation ] of Object.entries(path))
{
if (verb.startsWith('x-')) continue;
const operationId = operation.operationId;
const method = dotUtils.changeCase.snakeCase(operationId.slice(operationId.indexOf('.') + 1));
const resp200 = operation.responses['200'];
const isRso = (null != operation.security) && (null != operation.security[0]['rso']);
/* Return type checks. */
let hasReturn = false;
let returnType = '()';
let returnTypeTurbofish = '';
let returnOptional = false;
if (resp200 && resp200.content)
{
hasReturn = true;
const jsonInfo = resp200.content['application/json'];
const parseType = dotUtils.stringifyType(jsonInfo.schema, { fullpath: false });
returnTypeTurbofish = `::<${parseType}>`;
returnOptional = !!operation['x-nullable-404'];
returnType = returnOptional ? `Option<${parseType}>` : parseType;
}
/* Body content checks. */
let bodyType = null;
if (operation.requestBody)
{
const jsonInfo = operation.requestBody.content['application/json'];
bodyType = dotUtils.stringifyType(jsonInfo.schema, { fullpath: false });
}
/* Description processing. */
let descArr = operation.description.split('\n');
/* Build argument comment & string. */
const argBuilder = [
'route: ', dotUtils.changeCase.pascalCase(operation['x-route-enum']), 'Route'
];
if (isRso) {
argBuilder.push(', access_token: impl std::fmt::Display');
}
/* Add body params before path/query. */
if (bodyType) {
argBuilder.push(', body: &', bodyType);
}
/* Path and query params. */
const allParams = operation.parameters;
let queryParams = [];
let headerParams = [];
let routeArgument;
if (allParams && allParams.length)
{
const pathParams = allParams.filter(p => 'path' === p.in)
.sortBy(({ name }) => route.indexOf(name));
const reqQueryParams = allParams.filter(p => 'query' === p.in && p.required);
const optQueryParams = allParams.filter(p => 'query' === p.in && !p.required)
.sortBy(({ name }) => {
let match = /(^[a-z]+|[A-Z]+(?![a-z])|[A-Z][a-z]+)/.exec(name);
return match.slice(1).reverse().join('');
});
queryParams = reqQueryParams.concat(optQueryParams);
headerParams = allParams.filter(p => 'header' === p.in);
for (let paramList of [ pathParams, reqQueryParams, optQueryParams, headerParams ])
{
const required = paramList === pathParams;
for (const param of paramList)
{
argBuilder.push(', ', dotUtils.normalizePropName(param.name), ': ',
dotUtils.stringifyType(param.schema, { optional: !(required || param.required), owned: false }));
}
}
routeArgument = dotUtils.formatRouteArgument(route, pathParams);
}
else
{
routeArgument = dotUtils.formatRouteArgument(route);
}
for (var descLine of descArr)
{
}}
///{{= descLine ? ' ' + descLine : '' }}
{{
}
}}
/// # Parameters
/// * `route` - Route to query.
{{? isRso }}
/// * `access_token` - RSO access token.
{{?}}
{{~ allParams || [] :param }}
/// * `{{= dotUtils.changeCase.snakeCase(param.name) }}` ({{= param.required ? 'required' : 'optional' }}, in {{= param.in }}){{= param.description ? ' - ' + param.description : ''}}
{{~}}
{{? isRso }}
/// # RSO
/// This endpoint uses [Riot Sign On](https://developer.riotgames.com/docs/lol#rso-integration)
/// via the `access_token` parameter, instead of the Riot API key.
{{?}}
/// # Riot Developer API Reference
/// <a href="{{= operation.externalDocs.url }}" target="_blank">`{{= operationId }}`</a>
///
/// Note: this method is automatically generated.
pub fn {{= method }}(&self, {{= argBuilder.join('') }})
-> impl Future<Output = Result<{{= returnType }}>> + 'a
{
let route_str = route.into();
let request = self.base.request(Method::{{= verb.toUpperCase() }}, route_str, {{= routeArgument }});
{{? isRso }}
let mut request = request.bearer_auth(access_token);
if let Some(clear) = self.base.get_rso_clear_header() { request = request.header(clear, "") }
{{?}}
{{~ queryParams :queryParam }}
{{= dotUtils.formatAddQueryParam(queryParam) }}
{{~}}
{{~ headerParams :headerParam }}
{{= dotUtils.formatAddHeaderParam(headerParam) }}
{{~}}
{{? bodyType }}
let request = request
.body(serde_json::ser::to_vec(body).unwrap())
.header(reqwest::header::CONTENT_TYPE, "application/json");
{{?}}
let future = self.base.execute{{= hasReturn ? (returnOptional ? '_opt' : '_val') : '' }}{{= returnTypeTurbofish }}("{{= operationId }}", route_str, request);
#[cfg(feature = "tracing")]
let future = future.instrument(tracing::info_span!("{{= operationId }}", route = route_str));
#[cfg(feature = "metrics")]
let future = metrics::timed(future, "{{= operationId }}", route_str);
future
}
{{
}
}
}}
}
{{
}
}}

View file

@ -1,89 +0,0 @@
const util = require('util');
const fs = require('fs');
fs.readFileAsync = util.promisify(fs.readFile);
fs.writeFileAsync = util.promisify(fs.writeFile);
const req = require("request-promise-native");
process.chdir(__dirname);
const files = [
[
'http://raw.communitydragon.org/pbe/plugins/rcp-be-lol-game-data/global/default/v1/champion-summary.json',
'.champion.json'
],
[
'http://www.mingweisamuel.com/riotapi-schema/openapi-3.0.0.json',
'.spec.json'
],
[
'http://www.mingweisamuel.com/riotapi-schema/enums/seasons.json',
'.seasons.json'
],
[
'http://www.mingweisamuel.com/riotapi-schema/enums/queues.json',
'.queues.json'
],
[
'http://www.mingweisamuel.com/riotapi-schema/enums/queueTypes.json',
'.queueTypes.json'
],
[
'http://www.mingweisamuel.com/riotapi-schema/enums/gameTypes.json',
'.gameTypes.json'
],
[
'http://www.mingweisamuel.com/riotapi-schema/enums/gameModes.json',
'.gameModes.json'
],
[
'http://www.mingweisamuel.com/riotapi-schema/enums/maps.json',
'.maps.json'
],
[
'http://www.mingweisamuel.com/riotapi-schema/routesTable.json',
'.routesTable.json'
],
];
const downloadFilesPromise = Promise.all(files.map(([url, file]) => req(url)
.then(body => fs.writeFileAsync(file, body, "utf8"))));
const doT = require('dot');
const glob = require('glob-promise');
const log = a => { console.log(a); return a; };
const suffix = '.dt';
doT.templateSettings = {
evaluate: /\r?\n?\{\{([\s\S]+?)\}\}/g,
interpolate: /\r?\n?\{\{=([\s\S]+?)\}\}/g,
encode: /\r?\n?\{\{!([\s\S]+?)\}\}/g,
use: /\r?\n?\{\{#([\s\S]+?)\}\}/g,
define: /\r?\n?\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
conditional: /\r?\n?\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
iterate: /\r?\n?\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
varname: 'it',
strip: false,
append: false,
selfcontained: false
};
global.require = require;
downloadFilesPromise.then(() => glob.promise("**/*" + suffix, { ignore: ["**/node_modules/**"] }))
.then(files => Promise.all(files
.map(log)
.map(file => fs.readFileAsync(file, "utf8")
.then(input => {
try {
return doT.template(input)({});
}
catch (e) {
console.error(`Error thrown while running "${file}":`, e);
throw e;
}
})
.then(output => fs.writeFileAsync("../src/" + file.slice(0, -suffix.length), output, "utf8"))
)
))
.catch(console.error);

View file

@ -1,31 +0,0 @@
{{
const spec = require('./.spec.json');
const dotUtils = require('./dotUtils.js');
const operations = [];
for (const [ route, path ] of Object.entries(spec.paths)) {
for (const [ method, operation ] of Object.entries(path)) {
if (method.startsWith('x-')) continue;
operations.push({ route, method, operation });
}
}
}}{{= dotUtils.preamble() }}
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version {{= spec.info.version }}
//! Metadata about the Riot API and Riven.
//!
//! Note: this modules is automatically generated.
/// Metadata for endpoints. Each tuple corresponds to one endpoint and contains
/// the HTTP [`Method`](reqwest::Method), `str` path, and the method's `str` ID.
pub static ALL_ENDPOINTS: [(reqwest::Method, &str, &str); {{= operations.length }}] = [
{{
for (const { route, method, operation } of operations) {
}}
(reqwest::Method::{{= method.toUpperCase() }}, "{{= route }}", "{{= operation.operationId }}"),
{{
}
}}
];

View file

@ -1,97 +0,0 @@
{{
const spec = require('./.spec.json');
const dotUtils = require('./dotUtils.js');
}}{{= dotUtils.preamble() }}
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version {{= spec.info.version }}
#![allow(missing_docs)]
//! Data transfer structs.
//!
//! Separated into separate modules for each endpoint.
//! Several modules contain structs with the same name, so be sure to use the right ones.
//!
//! Note: these modules are automatically generated.
{{
let schemas = spec.components.schemas;
let schemaKeyByEndpoint = Object.keys(schemas)
.filter(schemaKey => 'Error' != schemaKey)
.groupBy(schemaKey => schemaKey.split('.')[0]);
for (let [endpoint, schemaKeyGroup] of schemaKeyByEndpoint) {
const endpoint_pascal_case = dotUtils.changeCase.pascalCase(endpoint);
}}
/// Data structs used by [`{{= endpoint_pascal_case }}`](crate::endpoints::{{= endpoint_pascal_case }}).
///
/// Note: this module is automatically generated.
#[allow(dead_code)]
pub mod {{= dotUtils.changeCase.snakeCase(endpoint) }} {
{{
for (let schemaKey of schemaKeyGroup) {
const [, rawSchemaName] = schemaKey.split('.');
const schemaName = dotUtils.normalizeSchemaName(rawSchemaName);
const schema = schemas[schemaKey];
const props = schema.properties;
const requiredSet = new Set(schema.required);
}}
/// `{{= endpoint }}.{{= rawSchemaName }}` data object.
{{? schema.description }}
/// # Description
/// {{= schema.description.replace(/https?:\/\/\S+[^\s\.!?]/g, "<$&>").split('\n').map(x => x.trim()).join('<br>\r\n /// ') }}
///
/// Note: This struct is automatically generated
{{?}}
#[derive(Clone, Debug)]
#[derive(serde::Serialize, crate::de::Deserialize)]
#[cfg_attr(feature = "deny-unknown-fields", serde(deny_unknown_fields))]
pub struct {{= schemaName }} {
{{
const usedNames = new Set();
for (let [ propKey, prop ] of Object.entries(props))
{
const optional = !requiredSet.has(propKey);
let name = dotUtils.normalizePropName(propKey);
while (usedNames.has(name)) {
name += '_';
}
usedNames.add(name);
}}
{{? prop.description }}
/// {{= prop.description.replace(/https?:\/\/\S+[^\s\.!?]/g, "<$&>").split('\n').map(x => x.trim()).join('<br>\r\n /// ') }}
{{?}}
{{= dotUtils.formatJsonProperty(propKey, prop) }}
{{? optional }}
#[serde(default, skip_serializing_if = "Option::is_none")]
{{?}}
{{? 'championId' === propKey && (prop.description || '').includes('this field returned invalid championIds') }}
///
/// Instead use [`Self::champion()`] which checks this field then parses [`Self::champion_name`].
#[deprecated(since = "2.5.0", note = "Use `Participant.champion()` instead. Riot sometimes returns corrupted data for this field: <https://github.com/RiotGames/developer-relations/issues/553>")]
#[serde(serialize_with = "crate::consts::Champion::serialize_result")]
#[serde(deserialize_with = "crate::consts::Champion::deserialize_result")]
pub {{= name }}: Result<crate::consts::Champion, std::num::TryFromIntError>,
{{?? 'gameType' === propKey && 'Info' === schemaName && 'match-v5' === endpoint }}
///
/// Will be `None` if empty string is returned: <https://github.com/RiotGames/developer-relations/issues/898>
#[serde(serialize_with = "crate::consts::serialize_empty_string_none")]
#[serde(deserialize_with = "crate::consts::deserialize_empty_string_none")]
pub {{= name }}: Option<crate::consts::GameType>,
{{??}}
pub {{= name }}: {{= dotUtils.stringifyType(prop, { optional }) }},
{{?}}
{{
}
}}
}
{{
}
}}
}
{{
}
}}

File diff suppressed because it is too large Load diff

View file

@ -1,20 +0,0 @@
{
"name": "dot-gen",
"version": "0.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"change-case": "^3.1.0",
"dot": "^1.1.3",
"glob": "^7.1.2",
"glob-promise": "^3.3.0",
"request": "^2.88.0",
"request-promise-native": "^1.0.7"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "GPL-2.0"
}

View file

@ -98,7 +98,7 @@ pub fn riot_api() -> &'static RiotApi {
std::path::PathBuf::from_iter([env!("CARGO_MANIFEST_DIR"), "../apikey.txt"]);
std::fs::read_to_string(path).ok()
})
.expect("Failed to find RGAPI_KEY env var or apikey.txt.");
.expect("Failed to find `RGAPI_KEY` env var or `apikey.txt`.");
RiotApi::new(RiotApiConfig::with_key(api_key.trim()).preconfig_burst())
})
}