added faction->chain, changed selections()
signature
This commit is contained in:
parent
c367c24606
commit
3df2d8e882
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "torn-api-macros"
|
name = "torn-api-macros"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Pyrit [2111649]"]
|
authors = ["Pyrit [2111649]"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
@ -44,7 +44,8 @@ fn impl_api_category(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
} else {
|
} else {
|
||||||
Err(meta.error("unknown attribute"))
|
Err(meta.error("unknown attribute"))
|
||||||
}
|
}
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +79,8 @@ fn impl_api_category(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
} else {
|
} else {
|
||||||
Err(meta.error("unsupported attribute"))
|
Err(meta.error("unsupported attribute"))
|
||||||
}
|
}
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
let name = format_ident!("{}", variant.ident.to_string().to_case(Case::Snake));
|
let name = format_ident!("{}", variant.ident.to_string().to_case(Case::Snake));
|
||||||
let raw_value = variant.ident.to_string().to_lowercase();
|
let raw_value = variant.ident.to_string().to_lowercase();
|
||||||
return Some(ApiAttribute {
|
return Some(ApiAttribute {
|
||||||
|
@ -87,8 +89,8 @@ fn impl_api_category(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
variant: variant.ident.clone(),
|
variant: variant.ident.clone(),
|
||||||
type_name: r#type.expect("type must be specified").parse().unwrap(),
|
type_name: r#type.expect("type must be specified").parse().unwrap(),
|
||||||
name,
|
name,
|
||||||
with
|
with,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
@ -154,7 +156,7 @@ fn impl_api_category(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::ApiSelection for #name {
|
impl crate::ApiSelection for #name {
|
||||||
fn raw_value(&self) -> &'static str {
|
fn raw_value(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
#(#raw_values,)*
|
#(#raw_values,)*
|
||||||
}
|
}
|
||||||
|
@ -180,19 +182,25 @@ fn to_static_lt(ty: &mut syn::Type) -> bool {
|
||||||
let mut res = false;
|
let mut res = false;
|
||||||
match ty {
|
match ty {
|
||||||
syn::Type::Path(path) => {
|
syn::Type::Path(path) => {
|
||||||
if let Some(syn::PathArguments::AngleBracketed(ab)) = path.path.segments.last_mut().map(|s| &mut s.arguments).as_mut() {
|
if let Some(syn::PathArguments::AngleBracketed(ab)) = path
|
||||||
|
.path
|
||||||
|
.segments
|
||||||
|
.last_mut()
|
||||||
|
.map(|s| &mut s.arguments)
|
||||||
|
.as_mut()
|
||||||
|
{
|
||||||
for mut arg in &mut ab.args {
|
for mut arg in &mut ab.args {
|
||||||
match &mut arg {
|
match &mut arg {
|
||||||
syn::GenericArgument::Type(ty) => {
|
syn::GenericArgument::Type(ty) => {
|
||||||
if to_static_lt(ty) {
|
if to_static_lt(ty) {
|
||||||
res = true;
|
res = true;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
syn::GenericArgument::Lifetime(lt) => {
|
syn::GenericArgument::Lifetime(lt) => {
|
||||||
lt.ident = syn::Ident::new("static", proc_macro2::Span::call_site());
|
lt.ident = syn::Ident::new("static", proc_macro2::Span::call_site());
|
||||||
res = true;
|
res = true;
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,7 +212,7 @@ fn to_static_lt(ty: &mut syn::Type) -> bool {
|
||||||
}
|
}
|
||||||
to_static_lt(&mut r.elem);
|
to_static_lt(&mut r.elem);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => (),
|
||||||
};
|
};
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
@ -223,7 +231,8 @@ fn impl_into_owned(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
} else {
|
} else {
|
||||||
Err(meta.error("unknown attribute"))
|
Err(meta.error("unknown attribute"))
|
||||||
}
|
}
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +244,8 @@ fn impl_into_owned(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.into()
|
}
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
let syn::Data::Struct(r#struct) = &ast.data else {
|
let syn::Data::Struct(r#struct) = &ast.data else {
|
||||||
|
@ -263,15 +273,21 @@ fn impl_into_owned(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
let vis = &field.vis;
|
let vis = &field.vis;
|
||||||
|
|
||||||
if to_static_lt(&mut ty) {
|
if to_static_lt(&mut ty) {
|
||||||
owned_fields.push(quote! { #vis #field_name: <#ty as crate::into_owned::IntoOwned>::Owned });
|
owned_fields
|
||||||
fields.push(quote! { #field_name: crate::into_owned::IntoOwned::into_owned(self.#field_name) });
|
.push(quote! { #vis #field_name: <#ty as crate::into_owned::IntoOwned>::Owned });
|
||||||
|
fields.push(
|
||||||
|
quote! { #field_name: crate::into_owned::IntoOwned::into_owned(self.#field_name) },
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
owned_fields.push(quote! { #vis #field_name: #ty });
|
owned_fields.push(quote! { #vis #field_name: #ty });
|
||||||
fields.push(quote! { #field_name: self.#field_name });
|
fields.push(quote! { #field_name: self.#field_name });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let owned_name = syn::Ident::new(&format!("{}Owned", ast.ident), proc_macro2::Span::call_site());
|
let owned_name = syn::Ident::new(
|
||||||
|
&format!("{}Owned", ast.ident),
|
||||||
|
proc_macro2::Span::call_site(),
|
||||||
|
);
|
||||||
|
|
||||||
let gen = quote! {
|
let gen = quote! {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "torn-api"
|
name = "torn-api"
|
||||||
version = "0.5.28"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Pyrit [2111649]"]
|
authors = ["Pyrit [2111649]"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -37,7 +37,7 @@ reqwest = { version = "0.11", default-features = false, features = [ "json" ], o
|
||||||
awc = { version = "3", default-features = false, optional = true }
|
awc = { version = "3", default-features = false, optional = true }
|
||||||
rust_decimal = { version = "1", default-features = false, optional = true, features = [ "serde" ] }
|
rust_decimal = { version = "1", default-features = false, optional = true, features = [ "serde" ] }
|
||||||
|
|
||||||
torn-api-macros = { path = "../torn-api-macros", version = "0.1.2" }
|
torn-api-macros = { path = "../torn-api-macros", version = "0.2" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = { version = "2.7.0" }
|
actix-rt = { version = "2.7.0" }
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
use serde::Deserialize;
|
use serde::{
|
||||||
|
de::{Error, Unexpected, Visitor},
|
||||||
|
Deserialize, Deserializer,
|
||||||
|
};
|
||||||
|
|
||||||
use torn_api_macros::{ApiCategory, IntoOwned};
|
use torn_api_macros::{ApiCategory, IntoOwned};
|
||||||
|
|
||||||
|
@ -28,6 +31,9 @@ pub enum FactionSelection {
|
||||||
with = "null_is_empty_dict"
|
with = "null_is_empty_dict"
|
||||||
)]
|
)]
|
||||||
Territory,
|
Territory,
|
||||||
|
|
||||||
|
#[api(type = "Option<Chain>", field = "chain", with = "deserialize_chain")]
|
||||||
|
Chain,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Selection = FactionSelection;
|
pub type Selection = FactionSelection;
|
||||||
|
@ -80,6 +86,128 @@ pub struct Basic<'a> {
|
||||||
pub territory_wars: Vec<FactionTerritoryWar<'a>>,
|
pub territory_wars: Vec<FactionTerritoryWar<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Chain {
|
||||||
|
pub current: i32,
|
||||||
|
pub max: i32,
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
pub modifier: rust_decimal::Decimal,
|
||||||
|
pub timeout: Option<i32>,
|
||||||
|
pub cooldown: Option<i32>,
|
||||||
|
pub start: DateTime<Utc>,
|
||||||
|
pub end: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_chain<'de, D>(deserializer: D) -> Result<Option<Chain>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct ChainVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for ChainVisitor {
|
||||||
|
type Value = Option<Chain>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("struct Chain")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
enum Fields {
|
||||||
|
Current,
|
||||||
|
Max,
|
||||||
|
Modifier,
|
||||||
|
Timeout,
|
||||||
|
Cooldown,
|
||||||
|
Start,
|
||||||
|
End,
|
||||||
|
#[serde(other)]
|
||||||
|
Ignore,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut current = None;
|
||||||
|
let mut max = None;
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
let mut modifier = None;
|
||||||
|
let mut timeout = None;
|
||||||
|
let mut cooldown = None;
|
||||||
|
let mut start = None;
|
||||||
|
let mut end = None;
|
||||||
|
|
||||||
|
while let Some(key) = map.next_key()? {
|
||||||
|
match key {
|
||||||
|
Fields::Current => {
|
||||||
|
let value = map.next_value()?;
|
||||||
|
if value != 0 {
|
||||||
|
current = Some(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Fields::Max => {
|
||||||
|
max = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
Fields::Modifier => {
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
{
|
||||||
|
modifier = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Fields::Timeout => {
|
||||||
|
match map.next_value()? {
|
||||||
|
0 => timeout = Some(None),
|
||||||
|
val => timeout = Some(Some(val)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Fields::Cooldown => {
|
||||||
|
match map.next_value()? {
|
||||||
|
0 => cooldown = Some(None),
|
||||||
|
val => cooldown = Some(Some(val)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Fields::Start => {
|
||||||
|
let ts: i64 = map.next_value()?;
|
||||||
|
start = Some(Utc.timestamp_opt(ts, 0).single().ok_or_else(|| {
|
||||||
|
A::Error::invalid_value(Unexpected::Signed(ts), &"Epoch timestamp")
|
||||||
|
})?);
|
||||||
|
}
|
||||||
|
Fields::End => {
|
||||||
|
let ts: i64 = map.next_value()?;
|
||||||
|
end = Some(Utc.timestamp_opt(ts, 0).single().ok_or_else(|| {
|
||||||
|
A::Error::invalid_value(Unexpected::Signed(ts), &"Epoch timestamp")
|
||||||
|
})?);
|
||||||
|
}
|
||||||
|
Fields::Ignore => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(current) = current else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
let max = max.ok_or_else(|| A::Error::missing_field("max"))?;
|
||||||
|
let timeout = timeout.ok_or_else(|| A::Error::missing_field("timeout"))?;
|
||||||
|
let cooldown = cooldown.ok_or_else(|| A::Error::missing_field("cooldown"))?;
|
||||||
|
let start = start.ok_or_else(|| A::Error::missing_field("start"))?;
|
||||||
|
let end = end.ok_or_else(|| A::Error::missing_field("end"))?;
|
||||||
|
|
||||||
|
Ok(Some(Chain {
|
||||||
|
current,
|
||||||
|
max,
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
modifier: modifier.ok_or_else(|| A::Error::missing_field("modifier"))?,
|
||||||
|
timeout,
|
||||||
|
cooldown,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_map(ChainVisitor)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -92,7 +220,12 @@ mod tests {
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.faction(|b| {
|
.faction(|b| {
|
||||||
b.selections(&[Selection::Basic, Selection::Attacks, Selection::Territory])
|
b.selections([
|
||||||
|
Selection::Basic,
|
||||||
|
Selection::Attacks,
|
||||||
|
Selection::Territory,
|
||||||
|
Selection::Chain,
|
||||||
|
])
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -101,6 +234,7 @@ mod tests {
|
||||||
response.attacks().unwrap();
|
response.attacks().unwrap();
|
||||||
response.attacks_full().unwrap();
|
response.attacks_full().unwrap();
|
||||||
response.territory().unwrap();
|
response.territory().unwrap();
|
||||||
|
response.chain().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_test]
|
#[async_test]
|
||||||
|
@ -111,13 +245,14 @@ mod tests {
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.faction(|b| {
|
.faction(|b| {
|
||||||
b.id(7049)
|
b.id(7049)
|
||||||
.selections(&[Selection::Basic, Selection::Territory])
|
.selections([Selection::Basic, Selection::Territory, Selection::Chain])
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
response.basic().unwrap();
|
response.basic().unwrap();
|
||||||
response.territory().unwrap();
|
response.territory().unwrap();
|
||||||
|
response.chain().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_test]
|
#[async_test]
|
||||||
|
@ -128,12 +263,13 @@ mod tests {
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.faction(|b| {
|
.faction(|b| {
|
||||||
b.id(8981)
|
b.id(8981)
|
||||||
.selections(&[Selection::Basic, Selection::Territory])
|
.selections([Selection::Basic, Selection::Territory, Selection::Chain])
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
response.basic().unwrap();
|
response.basic().unwrap();
|
||||||
response.territory().unwrap();
|
response.territory().unwrap();
|
||||||
|
assert!(response.chain().unwrap().is_none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,7 +247,7 @@ mod tests {
|
||||||
|
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.key(|b| b.selections(&[Selection::Info]))
|
.key(|b| b.selections([Selection::Info]))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,16 @@ pub enum ResponseError {
|
||||||
Api { code: u8, reason: String },
|
Api { code: u8, reason: String },
|
||||||
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Parsing(#[from] serde_json::Error),
|
MalformedResponse(#[from] serde_json::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResponseError {
|
||||||
|
pub fn api_code(&self) -> Option<u8> {
|
||||||
|
match self {
|
||||||
|
Self::Api { code, .. } => Some(*code),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApiResponse {
|
impl ApiResponse {
|
||||||
|
@ -100,7 +109,7 @@ impl ApiResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ApiSelection: Send + Sync {
|
pub trait ApiSelection: Send + Sync {
|
||||||
fn raw_value(&self) -> &'static str;
|
fn raw_value(self) -> &'static str;
|
||||||
|
|
||||||
fn category() -> &'static str;
|
fn category() -> &'static str;
|
||||||
}
|
}
|
||||||
|
@ -137,6 +146,18 @@ where
|
||||||
Response(#[from] ResponseError),
|
Response(#[from] ResponseError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<C> ApiClientError<C>
|
||||||
|
where
|
||||||
|
C: std::error::Error,
|
||||||
|
{
|
||||||
|
pub fn api_code(&self) -> Option<u8> {
|
||||||
|
match self {
|
||||||
|
Self::Response(err) => err.api_code(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ApiRequest<A>
|
pub struct ApiRequest<A>
|
||||||
where
|
where
|
||||||
|
@ -218,10 +239,13 @@ where
|
||||||
A: ApiSelection,
|
A: ApiSelection,
|
||||||
{
|
{
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn selections(mut self, selections: &[A]) -> Self {
|
pub fn selections(mut self, selections: impl IntoIterator<Item = A>) -> Self {
|
||||||
self.request
|
self.request.selections.append(
|
||||||
.selections
|
&mut selections
|
||||||
.append(&mut selections.iter().map(ApiSelection::raw_value).collect());
|
.into_iter()
|
||||||
|
.map(ApiSelection::raw_value)
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -222,7 +222,7 @@ mod tests {
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.torn(|b| {
|
.torn(|b| {
|
||||||
b.selections(&[
|
b.selections([
|
||||||
TornSelection::Competition,
|
TornSelection::Competition,
|
||||||
TornSelection::TerritoryWars,
|
TornSelection::TerritoryWars,
|
||||||
TornSelection::Rackets,
|
TornSelection::Rackets,
|
||||||
|
@ -242,7 +242,7 @@ mod tests {
|
||||||
|
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.torn(|b| b.selections(&[Selection::Territory]).id("NSC"))
|
.torn(|b| b.selections([Selection::Territory]).id("NSC"))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ mod tests {
|
||||||
|
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.torn(|b| b.selections(&[Selection::Territory]).id("AAA"))
|
.torn(|b| b.selections([Selection::Territory]).id("AAA"))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ mod tests {
|
||||||
|
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(&key)
|
.torn_api(&key)
|
||||||
.torn(|b| b.selections(&[Selection::TerritoryWarReport]).id(37403))
|
.torn(|b| b.selections([Selection::TerritoryWarReport]).id(37403))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ mod tests {
|
||||||
|
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(&key)
|
.torn_api(&key)
|
||||||
.torn(|b| b.selections(&[Selection::TerritoryWarReport]).id(37502))
|
.torn(|b| b.selections([Selection::TerritoryWarReport]).id(37502))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ mod tests {
|
||||||
|
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(&key)
|
.torn_api(&key)
|
||||||
.torn(|b| b.selections(&[Selection::TerritoryWarReport]).id(37860))
|
.torn(|b| b.selections([Selection::TerritoryWarReport]).id(37860))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -302,7 +302,7 @@ mod tests {
|
||||||
|
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(&key)
|
.torn_api(&key)
|
||||||
.torn(|b| b.selections(&[Selection::TerritoryWarReport]).id(23757))
|
.torn(|b| b.selections([Selection::TerritoryWarReport]).id(23757))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -145,8 +145,11 @@ pub struct Basic<'a> {
|
||||||
#[derive(Debug, Clone, IntoOwned, PartialEq, Eq, Deserialize)]
|
#[derive(Debug, Clone, IntoOwned, PartialEq, Eq, Deserialize)]
|
||||||
#[into_owned(identity)]
|
#[into_owned(identity)]
|
||||||
pub struct Discord {
|
pub struct Discord {
|
||||||
#[serde(rename = "userID")]
|
#[serde(
|
||||||
pub user_id: i32,
|
rename = "userID",
|
||||||
|
deserialize_with = "de_util::empty_string_int_option"
|
||||||
|
)]
|
||||||
|
pub user_id: Option<i32>,
|
||||||
#[serde(rename = "discordID", deserialize_with = "de_util::string_is_long")]
|
#[serde(rename = "discordID", deserialize_with = "de_util::string_is_long")]
|
||||||
pub discord_id: Option<i64>,
|
pub discord_id: Option<i64>,
|
||||||
}
|
}
|
||||||
|
@ -342,6 +345,7 @@ pub struct Profile<'a> {
|
||||||
pub last_action: LastAction,
|
pub last_action: LastAction,
|
||||||
#[serde(deserialize_with = "deserialize_faction")]
|
#[serde(deserialize_with = "deserialize_faction")]
|
||||||
pub faction: Option<Faction<'a>>,
|
pub faction: Option<Faction<'a>>,
|
||||||
|
pub job: EmploymentStatus,
|
||||||
pub status: Status<'a>,
|
pub status: Status<'a>,
|
||||||
|
|
||||||
#[serde(deserialize_with = "deserialize_comp")]
|
#[serde(deserialize_with = "deserialize_comp")]
|
||||||
|
@ -484,6 +488,104 @@ impl<'de> Deserialize<'de> for Icon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum Job {
|
||||||
|
Director,
|
||||||
|
Employee,
|
||||||
|
Education,
|
||||||
|
Army,
|
||||||
|
Law,
|
||||||
|
Casino,
|
||||||
|
Medical,
|
||||||
|
Grocer,
|
||||||
|
#[serde(other)]
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Company {
|
||||||
|
PlayerRun {
|
||||||
|
name: String,
|
||||||
|
id: i32,
|
||||||
|
company_type: u8,
|
||||||
|
},
|
||||||
|
CityJob,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Company {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct CompanyVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for CompanyVisitor {
|
||||||
|
type Value = Company;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("enum Company")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: MapAccess<'de>,
|
||||||
|
{
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
enum Field {
|
||||||
|
CompanyId,
|
||||||
|
CompanyName,
|
||||||
|
CompanyType,
|
||||||
|
#[serde(other)]
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut id = None;
|
||||||
|
let mut name = None;
|
||||||
|
let mut company_type = None;
|
||||||
|
|
||||||
|
while let Some(key) = map.next_key()? {
|
||||||
|
match key {
|
||||||
|
Field::CompanyId => {
|
||||||
|
id = Some(map.next_value()?);
|
||||||
|
if id == Some(0) {
|
||||||
|
return Ok(Company::CityJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Field::CompanyType => company_type = Some(map.next_value()?),
|
||||||
|
Field::CompanyName => {
|
||||||
|
name = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
Field::Other => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = id.ok_or_else(|| de::Error::missing_field("company_id"))?;
|
||||||
|
let name = name.ok_or_else(|| de::Error::missing_field("company_name"))?;
|
||||||
|
let company_type =
|
||||||
|
company_type.ok_or_else(|| de::Error::missing_field("company_type"))?;
|
||||||
|
|
||||||
|
Ok(Company::PlayerRun {
|
||||||
|
name,
|
||||||
|
id,
|
||||||
|
company_type,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_map(CompanyVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct EmploymentStatus {
|
||||||
|
pub job: Job,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub company: Company,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -496,7 +598,7 @@ mod tests {
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.user(|b| {
|
.user(|b| {
|
||||||
b.selections(&[
|
b.selections([
|
||||||
Selection::Basic,
|
Selection::Basic,
|
||||||
Selection::Discord,
|
Selection::Discord,
|
||||||
Selection::Profile,
|
Selection::Profile,
|
||||||
|
@ -523,7 +625,7 @@ mod tests {
|
||||||
|
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.user(|b| b.id(28).selections(&[Selection::Profile]))
|
.user(|b| b.id(28).selections([Selection::Profile]))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -539,7 +641,7 @@ mod tests {
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.users([1, 2111649, 374272176892674048i64], |b| {
|
.users([1, 2111649, 374272176892674048i64], |b| {
|
||||||
b.selections(&[Selection::Basic])
|
b.selections([Selection::Basic])
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -553,7 +655,7 @@ mod tests {
|
||||||
|
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.user(|b| b.id(374272176892674048i64).selections(&[Selection::Basic]))
|
.user(|b| b.id(374272176892674048i64).selections([Selection::Basic]))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -566,7 +668,7 @@ mod tests {
|
||||||
|
|
||||||
let response = Client::default()
|
let response = Client::default()
|
||||||
.torn_api(key)
|
.torn_api(key)
|
||||||
.user(|b| b.id(1900654).selections(&[Selection::Icons]))
|
.user(|b| b.id(1900654).selections([Selection::Icons]))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use async_trait::async_trait;
|
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use sqlx::{FromRow, PgPool, Postgres, QueryBuilder};
|
use sqlx::{FromRow, PgPool, Postgres, QueryBuilder};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
Loading…
Reference in a new issue