feat(codegen): derive Eq and Hash for most enum types

This commit is contained in:
pyrite 2025-05-27 19:56:03 +02:00
parent 1af37bea89
commit 3ad92fb8c8
Signed by: pyrite
GPG key ID: 7F1BA9170CD35D15
4 changed files with 583 additions and 277 deletions

View file

@ -8,7 +8,7 @@ use crate::openapi::{
r#type::{OpenApiType, OpenApiVariants},
};
use super::{object::PrimitiveType, ResolvedSchema};
use super::{object::PrimitiveType, Model, ResolvedSchema};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EnumRepr {
@ -143,6 +143,18 @@ impl EnumVariantTupleValue {
},
}
}
pub fn is_comparable(&self, resolved: &ResolvedSchema) -> bool {
match self {
Self::Primitive(_) => true,
Self::Enum { inner, .. } => inner.is_comparable(resolved),
Self::Ref { ty_name } | Self::ArrayOfRefs { ty_name } => resolved
.models
.get(ty_name)
.map(|m| matches!(m, Model::Newtype(_)))
.unwrap_or_default(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
@ -173,6 +185,13 @@ impl EnumVariantValue {
}
}
pub fn is_comparable(&self, resolved: &ResolvedSchema) -> bool {
match self {
Self::Repr(_) | Self::String { .. } => true,
Self::Tuple(values) => values.iter().all(|v| v.is_comparable(resolved)),
}
}
pub fn codegen_display(&self, name: &str) -> Option<TokenStream> {
let variant = format_ident!("{name}");
@ -417,6 +436,12 @@ impl Enum {
self.variants.iter().all(|v| v.value.is_display(resolved))
}
pub fn is_comparable(&self, resolved: &ResolvedSchema) -> bool {
self.variants
.iter()
.all(|v| v.value.is_comparable(resolved))
}
pub fn codegen(&self, resolved: &ResolvedSchema) -> Option<TokenStream> {
let repr = self.repr.map(|r| match r {
EnumRepr::U8 => quote! { #[repr(u8)]},
@ -458,7 +483,11 @@ impl Enum {
}
if self.copy {
derives.push(quote! { Copy, Hash });
derives.push(quote! { Copy });
}
if self.is_comparable(resolved) {
derives.push(quote! { Eq, Hash });
}
let serde_attr = self.untagged.then(|| {

View file

@ -315,7 +315,7 @@ The default value [Self::{}](self::{}#variant.{})"#,
let inner_ty = items.codegen_type_name(&inner_name);
code.extend(quote! {
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct #name(pub Vec<#inner_ty>);
impl std::fmt::Display for #name {

View file

@ -3,7 +3,7 @@
"info": {
"title": "Torn API",
"description": "\n * The development of Torn's API v2 is still ongoing.\n * If selections remain unaltered, they will default to the API v1 version.\n * Unlike API v1, API v2 accepts both selections and IDs as path and query parameters.\n * If any discrepancies or errors are found, please submit a [bug report](https://www.torn.com/forums.php#/p=forums&f=19&b=0&a=0) on the Torn Forums.\n * In case you're using bots to check for changes on openapi.json file, make sure to specificy a custom user-agent header - CloudFlare sometimes prevents requests from default user-agents.",
"version": "1.7.0"
"version": "1.8.0"
},
"servers": [
{
@ -1188,12 +1188,7 @@
"description": "Category of races returned",
"required": false,
"schema": {
"type": "string",
"default": "custom",
"enum": [
"official",
"custom"
]
"$ref": "#/components/schemas/RacingRaceTypeEnum"
}
},
{
@ -1504,7 +1499,17 @@
"description": "selection id",
"required": false,
"schema": {
"type": "string"
"oneOf": [
{
"$ref": "#/components/schemas/UserId"
},
{
"$ref": "#/components/schemas/TornCrimeId"
},
{
"type": "string"
}
]
}
},
{
@ -1522,10 +1527,23 @@
{
"name": "cat",
"in": "query",
"description": "Selection category",
"description": "Selection category. Can belong to one of the specified types.",
"required": false,
"schema": {
"type": "string"
"oneOf": [
{
"$ref": "#/components/schemas/ReportTypeEnum"
},
{
"$ref": "#/components/schemas/UserListEnum"
},
{
"$ref": "#/components/schemas/PersonalStatsCategoryEnum"
},
{
"$ref": "#/components/schemas/RacingRaceTypeEnum"
}
]
}
},
{
@ -1533,8 +1551,13 @@
"in": "query",
"description": "Selection stat",
"required": false,
"style": "form",
"explode": false,
"schema": {
"type": "string"
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonalStatsStatName"
}
}
},
{
@ -3021,6 +3044,51 @@
"x-stability": "Stable"
}
},
"/faction/search": {
"get": {
"tags": [
"Faction"
],
"summary": "Search factions by name or other criteria",
"description": "Requires public access key. <br>This selection is standalone and cannot be used together with other selections.",
"operationId": "01c192f9b41ce29372df54667bea2b43",
"parameters": [
{
"$ref": "#/components/parameters/ApiName"
},
{
"$ref": "#/components/parameters/ApiFactionSearchFilter"
},
{
"$ref": "#/components/parameters/ApiTimestamp"
},
{
"$ref": "#/components/parameters/ApiComment"
},
{
"$ref": "#/components/parameters/ApiKeyPublic"
}
],
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FactionSearchResponse"
}
}
}
}
},
"security": [
{
"api_key": []
}
],
"x-stability": "Unstable"
}
},
"/faction/stats": {
"get": {
"tags": [
@ -4644,71 +4712,6 @@
"x-stability": "Stable"
}
},
"/racing/races": {
"get": {
"tags": [
"Racing"
],
"summary": "Get races",
"description": "Requires public access key. <br>Returns a list of races, ordered by race start timestamp.",
"operationId": "4be921a67d32b5e82c68835ef56175d0",
"parameters": [
{
"$ref": "#/components/parameters/ApiLimit100"
},
{
"$ref": "#/components/parameters/ApiSortDesc"
},
{
"$ref": "#/components/parameters/ApiTo"
},
{
"$ref": "#/components/parameters/ApiFrom"
},
{
"name": "cat",
"in": "query",
"description": "Category of races returned",
"required": false,
"schema": {
"type": "string",
"default": "custom",
"enum": [
"official",
"custom"
]
}
},
{
"$ref": "#/components/parameters/ApiTimestamp"
},
{
"$ref": "#/components/parameters/ApiComment"
},
{
"$ref": "#/components/parameters/ApiKeyPublic"
}
],
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RacingRacesResponse"
}
}
}
}
},
"security": [
{
"api_key": []
}
],
"x-stability": "Stable"
}
},
"/racing/{raceId}/race": {
"get": {
"tags": [
@ -4960,7 +4963,14 @@
"description": "selection id",
"required": false,
"schema": {
"type": "string"
"oneOf": [
{
"$ref": "#/components/schemas/RaceId"
},
{
"$ref": "#/components/schemas/RaceTrackId"
}
]
}
},
{
@ -4981,7 +4991,14 @@
"description": "Selection category",
"required": false,
"schema": {
"type": "string"
"oneOf": [
{
"$ref": "#/components/schemas/RacingRaceTypeEnum"
},
{
"$ref": "#/components/schemas/RaceClassEnum"
}
]
}
},
{
@ -5972,7 +5989,26 @@
"description": "selection id",
"required": false,
"schema": {
"type": "string"
"oneOf": [
{
"$ref": "#/components/schemas/LogCategoryId"
},
{
"$ref": "#/components/schemas/TornCrimeId"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/ItemId"
}
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/FactionTerritoryEnum"
}
}
]
}
},
{
@ -5996,7 +6032,17 @@
"description": "Selection category",
"required": false,
"schema": {
"type": "string"
"oneOf": [
{
"$ref": "#/components/schemas/TornFactionHofCategory"
},
{
"$ref": "#/components/schemas/TornHofCategory"
},
{
"$ref": "#/components/schemas/TornItemCategory"
}
]
}
},
{
@ -10310,6 +10356,13 @@
"peace"
]
},
"RacingRaceTypeEnum": {
"type": "string",
"enum": [
"official",
"custom"
]
},
"FactionPositionAbilityEnum": {
"type": "string",
"enum": [
@ -10908,6 +10961,24 @@
7
]
},
"Parameters": {
"type": "string",
"oneOf": [
{
"type": "string",
"enum": [
"destroyed",
"notDestroyed",
"recruiting",
"notRecruiting"
]
},
{
"type": "string",
"pattern": "^(id|respect|members)(Equal|NotEqual|Less|LessOrEqual|GreaterOrEqual|Greater)\\d+$"
}
]
},
"ReviveSetting": {
"type": "string",
"enum": [
@ -12143,6 +12214,22 @@
},
"type": "object"
},
"SelectionCategoryEnum": {
"oneOf": [
{
"$ref": "#/components/schemas/ReportTypeEnum"
},
{
"$ref": "#/components/schemas/UserListEnum"
},
{
"$ref": "#/components/schemas/PersonalStatsCategoryEnum"
},
{
"$ref": "#/components/schemas/RacingRaceTypeEnum"
}
]
},
"UserCurrentEducation": {
"required": [
"id",
@ -13538,69 +13625,76 @@
"type": "object"
},
"UserSelectionName": {
"description": "The following selections will fallback to API v1 and may change at any time: 'ammo','bars','basic','battlestats','bazaar','cooldowns','criminalrecord','discord','display','education','equipment','events','gym','honors','icons','inventory','jobpoints','log','medals','merits','messages','missions','money','networth','newevents','newmessages','notifications','perks','profile','properties','refills','reports','skills','stocks','travel','weaponexp','workstats'.",
"type": "string",
"enum": [
"attacks",
"attacksfull",
"bounties",
"calendar",
"crimes",
"enlistedcars",
"factionbalance",
"forumfeed",
"forumfriends",
"forumposts",
"forumsubscribedthreads",
"forumthreads",
"hof",
"itemmarket",
"jobranks",
"list",
"lookup",
"organizedcrime",
"personalstats",
"races",
"revives",
"revivesfull",
"timestamp",
"ammo",
"bars",
"basic",
"battlestats",
"bazaar",
"cooldowns",
"criminalrecord",
"discord",
"display",
"education",
"equipment",
"events",
"gym",
"honors",
"icons",
"inventory",
"jobpoints",
"log",
"medals",
"merits",
"messages",
"missions",
"money",
"networth",
"newevents",
"newmessages",
"notifications",
"perks",
"profile",
"properties",
"refills",
"reports",
"skills",
"stocks",
"travel",
"weaponexp",
"workstats"
"oneOf": [
{
"description": "The following selections will fallback to API v1 and may change at any time: 'ammo','bars','basic','battlestats','bazaar','cooldowns','criminalrecord','discord','display','education','equipment','events','gym','honors','icons','inventory','jobpoints','log','medals','merits','messages','missions','money','networth','newevents','newmessages','notifications','perks','profile','properties','refills','reports','skills','stocks','travel','weaponexp','workstats'.",
"type": "string",
"enum": [
"attacks",
"attacksfull",
"bounties",
"calendar",
"crimes",
"enlistedcars",
"factionbalance",
"forumfeed",
"forumfriends",
"forumposts",
"forumsubscribedthreads",
"forumthreads",
"hof",
"itemmarket",
"jobranks",
"list",
"lookup",
"organizedcrime",
"personalstats",
"races",
"revives",
"revivesfull",
"timestamp",
"ammo",
"bars",
"basic",
"battlestats",
"bazaar",
"cooldowns",
"criminalrecord",
"discord",
"display",
"education",
"equipment",
"events",
"gym",
"honors",
"icons",
"inventory",
"jobpoints",
"log",
"medals",
"merits",
"messages",
"missions",
"money",
"networth",
"newevents",
"newmessages",
"notifications",
"perks",
"profile",
"properties",
"refills",
"reports",
"skills",
"stocks",
"travel",
"weaponexp",
"workstats"
]
},
{
"type": "string"
}
]
},
"UserLookupResponse": {
@ -16680,6 +16774,120 @@
},
"type": "object"
},
"FactionSearchLeader": {
"required": [
"id",
"name"
],
"properties": {
"id": {
"$ref": "#/components/schemas/UserId"
},
"name": {
"type": "string"
}
},
"type": "object"
},
"FactionSearch": {
"required": [
"id",
"name",
"respect",
"members",
"leader",
"co_leader",
"image",
"tag_image",
"tag",
"is_destroyed",
"is_recruiting"
],
"properties": {
"id": {
"$ref": "#/components/schemas/FactionId"
},
"name": {
"type": "string"
},
"respect": {
"type": "integer",
"format": "int32"
},
"members": {
"type": "integer",
"format": "int32"
},
"leader": {
"$ref": "#/components/schemas/FactionSearchLeader"
},
"co_leader": {
"oneOf": [
{
"$ref": "#/components/schemas/FactionSearchLeader"
},
{
"type": "null"
}
]
},
"image": {
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"tag_image": {
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"tag": {
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"is_destroyed": {
"type": "boolean"
},
"is_recruiting": {
"type": "boolean"
}
},
"type": "object"
},
"FactionSearchResponse": {
"required": [
"search",
"_metadata"
],
"properties": {
"search": {
"type": "array",
"items": {
"$ref": "#/components/schemas/FactionSearch"
}
},
"_metadata": {
"$ref": "#/components/schemas/RequestMetadataWithLinks"
}
},
"type": "object"
},
"FactionTerritoryWarFinished": {
"required": [
"id",
@ -18905,57 +19113,56 @@
"type": "object"
},
"FactionSelectionName": {
"description": "The following selections will fallback to API v1 and may change at any time: 'armor', 'boosters', 'caches', 'cesium', 'crimeexp', 'drugs', 'medical', 'positions', 'reports', 'temporary', 'weapons'.\n * The following selections are not available in API v2: 'armorynews', 'attacknews', 'crimenews', 'currency', 'donations', 'fundsnews', 'mainnews', 'membershipnews', 'territorynews'.",
"type": "string",
"enum": [
"applications",
"attacks",
"attacksfull",
"balance",
"basic",
"chain",
"chainreport",
"chains",
"contributors",
"crime",
"crimes",
"hof",
"lookup",
"members",
"news",
"rackets",
"rankedwars",
"rankedwarreport",
"revives",
"revivesfull",
"stats",
"territory",
"territoryownership",
"territorywarreport",
"territorywars",
"timestamp",
"upgrades",
"wars",
"armor",
"boosters",
"caches",
"cesium",
"crimeexp",
"drugs",
"medical",
"positions",
"reports",
"temporary",
"weapons",
"armorynews",
"attacknews",
"crimenews",
"currency",
"donations",
"fundsnews",
"mainnews",
"membershipnews",
"territorynews"
"oneOf": [
{
"description": "The following selections will fallback to API v1 and may change at any time: 'armor', 'boosters', 'caches', 'cesium', 'crimeexp', 'drugs', 'medical', 'temporary', 'weapons'.\n * The following selections are not available in API v2: 'armorynews', 'attacknews', 'crimenews', 'currency', 'donations', 'fundsnews', 'mainnews', 'membershipnews', 'territorynews'.",
"type": "string",
"enum": [
"applications",
"attacks",
"attacksfull",
"balance",
"basic",
"chain",
"chainreport",
"chains",
"contributors",
"crime",
"crimes",
"hof",
"lookup",
"members",
"news",
"positions",
"rackets",
"rankedwars",
"rankedwarreport",
"reports",
"revives",
"revivesfull",
"search",
"stats",
"territory",
"territoryownership",
"territorywarreport",
"territorywars",
"timestamp",
"upgrades",
"wars",
"armor",
"boosters",
"caches",
"cesium",
"crimeexp",
"drugs",
"medical",
"temporary",
"weapons"
]
},
{
"type": "string"
}
]
},
"FactionLookupResponse": {
@ -19669,14 +19876,21 @@
"type": "object"
},
"ForumSelectionName": {
"type": "string",
"enum": [
"categories",
"lookup",
"posts",
"thread",
"threads",
"timestamp"
"oneOf": [
{
"type": "string",
"enum": [
"categories",
"lookup",
"posts",
"thread",
"threads",
"timestamp"
]
},
{
"type": "string"
}
]
},
"ForumLookupResponse": {
@ -19725,6 +19939,9 @@
"type": "integer",
"format": "int64"
},
{
"type": "string"
},
{
"type": "null"
}
@ -19882,10 +20099,17 @@
"type": "object"
},
"KeySelectionName": {
"type": "string",
"enum": [
"info",
"log"
"oneOf": [
{
"type": "string",
"enum": [
"info",
"log"
]
},
{
"type": "string"
}
]
},
"ItemMarketListingItemBonus": {
@ -20102,14 +20326,21 @@
"type": "object"
},
"MarketSelectionName": {
"description": "The following selections will fallback to API v1 and may change at any time: 'pointsmarket'.",
"type": "string",
"enum": [
"itemmarket",
"lookup",
"timestamp",
"pointsmarket",
"bazaar"
"oneOf": [
{
"description": "The following selections will fallback to API v1 and may change at any time: 'pointsmarket'.",
"type": "string",
"enum": [
"itemmarket",
"lookup",
"timestamp",
"pointsmarket",
"bazaar"
]
},
{
"type": "string"
}
]
},
"MarketLookupResponse": {
@ -20650,16 +20881,23 @@
"type": "object"
},
"RacingSelectionName": {
"type": "string",
"enum": [
"cars",
"carupgrades",
"lookup",
"race",
"races",
"records",
"timestamp",
"tracks"
"oneOf": [
{
"type": "string",
"enum": [
"cars",
"carupgrades",
"lookup",
"race",
"races",
"records",
"timestamp",
"tracks"
]
},
{
"type": "string"
}
]
},
"RacingLookupResponse": {
@ -22078,55 +22316,55 @@
"type": "object"
},
"TornSelectionName": {
"description": "The following selections will fallback to API v1 and may change at any time: 'bank','cards','cityshops','companies','competition','dirtybombs','gyms','honors','itemdetails','itemstats','medals','organisedcrimes','pawnshop','pokertables','properties','raidreport','raids','rockpaperscissors','searchforcash','shoplifting','stats','stocks'.\n * The following selections are not available in API v2: 'chainreport', 'rackets', 'rankedwarreport', 'rankedwars', 'territorynames', 'territorywarreport', 'territorywars'.",
"type": "string",
"enum": [
"attacklog",
"bounties",
"calendar",
"crimes",
"education",
"factionhof",
"factiontree",
"hof",
"itemammo",
"itemmods",
"items",
"logcategories",
"logtypes",
"lookup",
"subcrimes",
"territory",
"timestamp",
"bank",
"cards",
"cityshops",
"companies",
"competition",
"dirtybombs",
"gyms",
"honors",
"itemdetails",
"itemstats",
"medals",
"organisedcrimes",
"pawnshop",
"pokertables",
"properties",
"raidreport",
"raids",
"rockpaperscissors",
"searchforcash",
"shoplifting",
"stats",
"stocks",
"chainreport",
"rackets",
"rankedwarreport",
"rankedwars",
"territorynames",
"territorywarreport",
"territorywars"
"oneOf": [
{
"description": "The following selections will fallback to API v1 and may change at any time: 'bank','cards','cityshops','companies','competition','dirtybombs','gyms','honors','itemdetails','itemstats','medals','organisedcrimes','pawnshop','pokertables','properties','raidreport','raids','rockpaperscissors','searchforcash','shoplifting','stats','stocks'.\n * The following selections are not available in API v2: 'chainreport', 'rackets', 'rankedwarreport', 'rankedwars', 'territorynames', 'territorywarreport', 'territorywars'.",
"type": "string",
"enum": [
"attacklog",
"bounties",
"calendar",
"crimes",
"education",
"factionhof",
"factiontree",
"hof",
"itemammo",
"itemmods",
"items",
"logcategories",
"logtypes",
"lookup",
"subcrimes",
"territory",
"timestamp",
"bank",
"cards",
"cityshops",
"companies",
"competition",
"dirtybombs",
"gyms",
"honors",
"itemdetails",
"itemstats",
"medals",
"organisedcrimes",
"pawnshop",
"pokertables",
"properties",
"raidreport",
"raids",
"rockpaperscissors",
"searchforcash",
"shoplifting",
"stats",
"stocks"
]
},
{
"type": "string"
}
]
},
"TornLookupResponse": {
@ -22181,6 +22419,36 @@
"type": "string"
}
},
"ApiFactionSearchFilter": {
"name": "filters",
"in": "query",
"description": "A filtering query parameter allowing a comma-separated list of filters. <br>\n * Each filter can be one of the following:\n * Fixed options: 'destroyed', 'notDestroyed', 'recruiting', 'notRecruiting'\n * Dynamic options: `fieldName`+`condition`+`number`, where:\n * * `fieldName` is one of: `id`, `respect`, `members`\n * * `condition` is one of: `Equal`, `NotEqual`, `Less`, `LessOrEqual`, `GreaterOrEqual`, `Greater`\n * * `number`: any integer value\n * Examples: `filters=destroyed`, `filters=notDestroyed,recruiting`, `filters=respectLessOrEqual20000,idGreater100,notRecruiting`",
"required": false,
"style": "form",
"explode": false,
"schema": {
"type": "array",
"items": {
"schema": "Parameters",
"type": "string",
"oneOf": [
{
"type": "string",
"enum": [
"destroyed",
"notDestroyed",
"recruiting",
"notRecruiting"
]
},
{
"type": "string",
"pattern": "^(id|respect|members)(Equal|NotEqual|Less|LessOrEqual|GreaterOrEqual|Greater)\\d+$"
}
]
}
}
},
"ApiComment": {
"name": "comment",
"in": "query",
@ -22190,6 +22458,15 @@
"type": "string"
}
},
"ApiName": {
"name": "name",
"in": "query",
"description": "Name to search for.",
"required": false,
"schema": {
"type": "string"
}
},
"ApiLimit20": {
"name": "limit",
"in": "query",

View file

@ -9,7 +9,7 @@ pub(super) mod test {
use crate::{
executor::{ExecutorExt, ReqwestClient},
models::{
faction_selection_name::FactionSelectionNameVariant, AttackCode, FactionSelectionName,
faction_selection_name::FactionSelectionNameVariant, AttackCode,
PersonalStatsCategoryEnum, PersonalStatsStatName, UserListEnum,
},
};