Skip to main content

pogo_masterfile_types/
lib.rs

1//! Generated Rust types for the Pokémon GO masterfile.
2//!
3//! # Quick start
4//!
5//! ```no_run
6//! use pogo_masterfile_types::{parse_masterfile, MasterfileEntry};
7//!
8//! let json = std::fs::read_to_string("masterfile.json").unwrap();
9//! let entries = parse_masterfile(&json).unwrap();
10//! for entry in entries {
11//!     match entry {
12//!         MasterfileEntry::PokemonSettings(e) => {
13//!             println!("pokémon: {}", e.template_id);
14//!         }
15//!         _ => {}
16//!     }
17//! }
18//! ```
19//!
20//! # Generated structure
21//!
22//! Each masterfile discriminator maps to its own module containing three
23//! types:
24//!
25//! - **`Entry`** (e.g. [`pokemon_settings::PokemonSettingsEntry`]): the outer
26//!   JSON shape, `{ templateId, data: { ... } }`.
27//! - **`EntryData`** (e.g. [`pokemon_settings::PokemonSettingsEntryData`]): the
28//!   inner `data` object, with the discriminator-keyed payload field.
29//! - **The payload type** (e.g. [`pokemon_settings::PokemonSettings`]): the
30//!   shape of the payload itself. For multi-shape groups this is a Rust
31//!   enum dispatching to per-cluster variant structs.
32//!
33//! Singletons (entries unique by `templateId`) are bundled into a single
34//! [`singletons`] module rather than emitted one file each.
35
36#![allow(clippy::large_enum_variant)]
37
38// Aliases the crate to its own name so the FromStrEnum-derived
39// `impl FromStr` paths resolve inside this crate (where they reference
40// `pogo_masterfile_types::UnknownTemplateId`). External consumers don't
41// need this — their crate name is already in their extern prelude.
42extern crate self as pogo_masterfile_types;
43
44use serde::{Deserialize, Serialize};
45
46pub use pogo_masterfile_macros::{AllVariants, AsStr, FromStrEnum, TemplateId};
47
48/// Error returned by `FromStr` impls on generated templateId enums when the
49/// input string does not match any known templateId for the group.
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct UnknownTemplateId(pub String);
52
53impl core::fmt::Display for UnknownTemplateId {
54    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55        write!(f, "unknown templateId: {}", self.0)
56    }
57}
58
59impl std::error::Error for UnknownTemplateId {}
60
61/// Defines an Entry + EntryData pair for a discriminator that carries a payload.
62/// Used by the codegen; consumers of this crate normally don't invoke directly.
63#[macro_export]
64macro_rules! masterfile_entry {
65    ($entry:ident, $data:ident, $field:ident: $ty:ty) => {
66        /// Outer masterfile wrapper: `{ templateId, data: { ... } }`.
67        #[derive(Debug, Clone, ::serde::Serialize, ::serde::Deserialize)]
68        #[serde(rename_all = "camelCase")]
69        pub struct $entry {
70            pub template_id: String,
71            pub data: $data,
72        }
73        /// Inner `data` object: `{ templateId, [discriminator]: payload }`.
74        #[derive(Debug, Clone, ::serde::Serialize, ::serde::Deserialize)]
75        #[serde(rename_all = "camelCase")]
76        pub struct $data {
77            pub template_id: String,
78            pub $field: $ty,
79        }
80    };
81}
82
83/// Defines an Entry + EntryData pair for a stub discriminator (no payload).
84/// Stub entries have JSON shape `{ templateId, data: { templateId } }`.
85#[macro_export]
86macro_rules! masterfile_stub_entry {
87    ($entry:ident, $data:ident) => {
88        /// Outer masterfile wrapper for a stub entry (no payload).
89        #[derive(Debug, Clone, ::serde::Serialize, ::serde::Deserialize)]
90        #[serde(rename_all = "camelCase")]
91        pub struct $entry {
92            pub template_id: String,
93            pub data: $data,
94        }
95        /// Inner `data` object for a stub entry: `{ templateId }`.
96        #[derive(Debug, Clone, ::serde::Serialize, ::serde::Deserialize)]
97        #[serde(rename_all = "camelCase")]
98        pub struct $data {
99            pub template_id: String,
100        }
101    };
102}
103
104pub mod avatar_customization;
105pub mod avatar_group_order_settings;
106pub mod avatar_item_display;
107pub mod badge_settings;
108pub mod bread_move_level_settings;
109pub mod buddy_activity_category_settings;
110pub mod buddy_emotion_level_settings;
111pub mod buddy_level_settings;
112pub mod client_quest_template;
113pub mod code_gate_proto;
114pub mod combat_league;
115pub mod combat_move;
116pub mod combat_npc_personality;
117pub mod combat_npc_trainer;
118pub mod combat_ranking_proto_settings;
119pub mod combat_type;
120pub mod event_pass_settings;
121pub mod event_pass_tier_settings;
122pub mod evolution_chain_display_settings;
123pub mod evolution_quest_template;
124pub mod feature_gate;
125pub mod form_settings;
126pub mod fort_power_up_level_settings;
127pub mod friendship_milestone_settings;
128pub mod gender_settings;
129pub mod iap_category_display;
130pub mod iap_item_display;
131pub mod invasion_npc_display_settings;
132pub mod item_expiration_settings;
133pub mod item_settings;
134pub mod language_settings;
135pub mod level_up_rewards;
136pub mod limited_purchase_sku_settings;
137pub mod location_card_settings;
138pub mod mega_evo_level_settings;
139pub mod move_sequence_settings;
140pub mod move_settings;
141pub mod non_combat_move_settings;
142pub mod party_play_general_settings;
143pub mod photo_sets_settings_proto;
144pub mod pokemon_extended_settings;
145pub mod pokemon_family;
146pub mod pokemon_home_energy_costs;
147pub mod pokemon_home_form_reversions;
148pub mod pokemon_scale_settings;
149pub mod pokemon_settings;
150pub mod pokemon_upgrades;
151pub mod pokestop_invasion_availability_settings;
152pub mod quest_settings;
153pub mod recommended_search_settings;
154pub mod roll_back;
155pub mod settings_override_rule;
156pub mod singletons;
157pub mod sticker_metadata;
158pub mod tappable_settings;
159pub mod temporary_evolution_settings;
160pub mod type_effective;
161pub mod vs_seeker_loot;
162pub mod vs_seeker_pokemon_rewards;
163pub mod weather_affinities;
164
165/// Every typed entry the Pokémon GO masterfile can hold.
166///
167/// Variants are ordered most-frequent-first (by entry count in the source
168/// masterfile). Serialization uses `#[serde(untagged)]` so the JSON shape
169/// round-trips as the inner Entry struct directly. Deserialization is a
170/// custom impl that peeks at `data`'s non-`templateId` key for O(1)
171/// dispatch — see the impl below.
172///
173/// **Caveat:** stub entries (the few discriminators with
174/// `data: { templateId }` only) are shape-indistinguishable. They all
175/// dispatch via `templateId` value match in the deserializer; inspect
176/// `template_id` post-parse if you need to branch on the specific kind.
177#[derive(Debug, Clone, Serialize, TemplateId)]
178#[serde(untagged)]
179pub enum MasterfileEntry {
180    PokemonExtendedSettings(pokemon_extended_settings::PokemonExtendedSettingsEntry),
181    GenderSettings(gender_settings::GenderSettingsEntry),
182    PokemonSettings(pokemon_settings::PokemonSettingsEntry),
183    AvatarCustomization(avatar_customization::AvatarCustomizationEntry),
184    AvatarItemDisplay(avatar_item_display::AvatarItemDisplayEntry),
185    IapItemDisplay(iap_item_display::IapItemDisplayEntry),
186    FormSettings(form_settings::FormSettingsEntry),
187    BadgeSettings(badge_settings::BadgeSettingsEntry),
188    StickerMetadata(sticker_metadata::StickerMetadataEntry),
189    PokemonFamily(pokemon_family::PokemonFamilyEntry),
190    EventPassTierSettings(event_pass_tier_settings::EventPassTierSettingsEntry),
191    MoveSettings(move_settings::MoveSettingsEntry),
192    MoveSequenceSettings(move_sequence_settings::MoveSequenceSettingsEntry),
193    CombatMove(combat_move::CombatMoveEntry),
194    SettingsOverrideRule(settings_override_rule::SettingsOverrideRuleEntry),
195    LocationCardSettings(location_card_settings::LocationCardSettingsEntry),
196    ItemSettings(item_settings::ItemSettingsEntry),
197    CombatLeague(combat_league::CombatLeagueEntry),
198    MegaEvoLevelSettings(mega_evo_level_settings::MegaEvoLevelSettingsEntry),
199    LevelUpRewards(level_up_rewards::LevelUpRewardsEntry),
200    EvolutionChainDisplaySettings(
201        evolution_chain_display_settings::EvolutionChainDisplaySettingsEntry,
202    ),
203    InvasionNpcDisplaySettings(invasion_npc_display_settings::InvasionNpcDisplaySettingsEntry),
204    ClientQuestTemplate(client_quest_template::ClientQuestTemplateEntry),
205    TemporaryEvolutionSettings(temporary_evolution_settings::TemporaryEvolutionSettingsEntry),
206    VsSeekerLoot(vs_seeker_loot::VsSeekerLootEntry),
207    PhotoSetsSettingsProto(photo_sets_settings_proto::PhotoSetsSettingsProtoEntry),
208    EvolutionQuestTemplate(evolution_quest_template::EvolutionQuestTemplateEntry),
209    LimitedPurchaseSkuSettings(limited_purchase_sku_settings::LimitedPurchaseSkuSettingsEntry),
210    CombatRankingProtoSettings(combat_ranking_proto_settings::CombatRankingProtoSettingsEntry),
211    ItemExpirationSettings(item_expiration_settings::ItemExpirationSettingsEntry),
212    CombatType(combat_type::CombatTypeEntry),
213    TypeEffective(type_effective::TypeEffectiveEntry),
214    IapCategoryDisplay(iap_category_display::IapCategoryDisplayEntry),
215    CodeGateProto(code_gate_proto::CodeGateProtoEntry),
216    FeatureGate(feature_gate::FeatureGateEntry),
217    RecommendedSearchSettings(recommended_search_settings::RecommendedSearchSettingsEntry),
218    CombatNpcTrainer(combat_npc_trainer::CombatNpcTrainerEntry),
219    NonCombatMoveSettings(non_combat_move_settings::NonCombatMoveSettingsEntry),
220    BuddyActivityCategorySettings(
221        buddy_activity_category_settings::BuddyActivityCategorySettingsEntry,
222    ),
223    BreadMoveLevelSettings(bread_move_level_settings::BreadMoveLevelSettingsEntry),
224    BuddyEmotionLevelSettings(buddy_emotion_level_settings::BuddyEmotionLevelSettingsEntry),
225    PokemonHomeFormReversions(pokemon_home_form_reversions::PokemonHomeFormReversionsEntry),
226    PokestopInvasionAvailabilitySettings(
227        pokestop_invasion_availability_settings::PokestopInvasionAvailabilitySettingsEntry,
228    ),
229    WeatherAffinities(weather_affinities::WeatherAffinitiesEntry),
230    FriendshipMilestoneSettings(friendship_milestone_settings::FriendshipMilestoneSettingsEntry),
231    PokemonScaleSettings(pokemon_scale_settings::PokemonScaleSettingsEntry),
232    BuddyLevelSettings(buddy_level_settings::BuddyLevelSettingsEntry),
233    TappableSettings(tappable_settings::TappableSettingsEntry),
234    FortPowerUpLevelSettings(fort_power_up_level_settings::FortPowerUpLevelSettingsEntry),
235    PokemonHomeEnergyCosts(pokemon_home_energy_costs::PokemonHomeEnergyCostsEntry),
236    CombatNpcPersonality(combat_npc_personality::CombatNpcPersonalityEntry),
237    LanguageSettings(language_settings::LanguageSettingsEntry),
238    QuestSettings(quest_settings::QuestSettingsEntry),
239    RollBack(roll_back::RollBackEntry),
240    AvatarGroupOrderSettings(avatar_group_order_settings::AvatarGroupOrderSettingsEntry),
241    EventPassSettings(event_pass_settings::EventPassSettingsEntry),
242    PartyPlayGeneralSettings(party_play_general_settings::PartyPlayGeneralSettingsEntry),
243    PokemonUpgrades(pokemon_upgrades::PokemonUpgradesEntry),
244    VsSeekerPokemonRewards(vs_seeker_pokemon_rewards::VsSeekerPokemonRewardsEntry),
245    AccessibilitySettings(singletons::AccessibilitySettingsEntry),
246    AdditiveSceneSettings(singletons::AdditiveSceneSettingsEntry),
247    AddressablePokemonSettings(singletons::AddressablePokemonSettingsEntry),
248    AddressBookImportSettings(singletons::AddressBookImportSettingsEntry),
249    AdvancedSettings(singletons::AdvancedSettingsEntry),
250    AmuseBoucheWelcomeBackRewards(singletons::AmuseBoucheWelcomeBackRewardsEntry),
251    ArPhotoFeatureFlags(singletons::ArPhotoFeatureFlagsEntry),
252    ArTelemetrySettings(singletons::ArTelemetrySettingsEntry),
253    AssetRefreshProto(singletons::AssetRefreshProtoEntry),
254    AvatarFeatureFlags(singletons::AvatarFeatureFlagsEntry),
255    AvatarStoreFooterFlags(singletons::AvatarStoreFooterFlagsEntry),
256    AvatarStoreSubcategoryFilteringFlags(singletons::AvatarStoreSubcategoryFilteringFlagsEntry),
257    BackgroundModeSettings(singletons::BackgroundModeSettingsEntry),
258    BattleAnimationSettings(singletons::BattleAnimationSettingsEntry),
259    BattleHubBadgeSettings(singletons::BattleHubBadgeSettingsEntry),
260    BattleHubOrderSettings(singletons::BattleHubOrderSettingsEntry),
261    BattleInputBufferSettings(singletons::BattleInputBufferSettingsEntry),
262    BattlePartySettings(singletons::BattlePartySettingsEntry),
263    BattleSettings(singletons::BattleSettingsEntry),
264    BattleVisualSettings(singletons::BattleVisualSettingsEntry),
265    BelugaPokemonWhitelist(singletons::BelugaPokemonWhitelistEntry),
266    BestFriendsPlusSettings(singletons::BestFriendsPlusSettingsEntry),
267    BreadBattleClientSettings(singletons::BreadBattleClientSettingsEntry),
268    BreadFeatureFlags(singletons::BreadFeatureFlagsEntry),
269    BreadLobbyCounterSettings(singletons::BreadLobbyCounterSettingsEntry),
270    BreadLobbyUpdateSettings(singletons::BreadLobbyUpdateSettingsEntry),
271    BreadMoveMappings(singletons::BreadMoveMappingsEntry),
272    BreadPokemonScalingSettings(singletons::BreadPokemonScalingSettingsEntry),
273    BreadSettings(singletons::BreadSettingsEntry),
274    BuddyEncounterCameoSettings(singletons::BuddyEncounterCameoSettingsEntry),
275    BuddyHungerSettings(singletons::BuddyHungerSettingsEntry),
276    BuddyInteractionSettings(singletons::BuddyInteractionSettingsEntry),
277    BuddySwapSettings(singletons::BuddySwapSettingsEntry),
278    BuddyWalkSettings(singletons::BuddyWalkSettingsEntry),
279    BulkHealingSettings(singletons::BulkHealingSettingsEntry),
280    ButterflyCollectorSettings(singletons::ButterflyCollectorSettingsEntry),
281    CampfireSettings(singletons::CampfireSettingsEntry),
282    CatchRadiusMultiplierSettings(singletons::CatchRadiusMultiplierSettingsEntry),
283    CombatCompetitiveSeasonSettings(singletons::CombatCompetitiveSeasonSettingsEntry),
284    CombatLeagueSettings(singletons::CombatLeagueSettingsEntry),
285    CombatSettings(singletons::CombatSettingsEntry),
286    CombatStatStageSettings(singletons::CombatStatStageSettingsEntry),
287    ContestSettings(singletons::ContestSettingsEntry),
288    ConversationSettings(singletons::ConversationSettingsEntry),
289    CrossGameSocialSettings(singletons::CrossGameSocialSettingsEntry),
290    DailyAdventureIncenseSettings(singletons::DailyAdventureIncenseSettingsEntry),
291    DeepLinkingSettings(singletons::DeepLinkingSettingsEntry),
292    EggHatchImprovementsSettings(singletons::EggHatchImprovementsSettingsEntry),
293    EncounterSettings(singletons::EncounterSettingsEntry),
294    ErrorReportingSettings(singletons::ErrorReportingSettingsEntry),
295    EventPlannerPopularNotificationSettings(
296        singletons::EventPlannerPopularNotificationSettingsEntry,
297    ),
298    EventServerSettings(singletons::EventServerSettingsEntry),
299    ExternalAddressableAssetsSettings(singletons::ExternalAddressableAssetsSettingsEntry),
300    FeatureUnlockLevelSettings(singletons::FeatureUnlockLevelSettingsEntry),
301    GeotargetedQuestSettings(singletons::GeotargetedQuestSettingsEntry),
302    GiftingSettings(singletons::GiftingSettingsEntry),
303    GuiSearchSettings(singletons::GuiSearchSettingsEntry),
304    GymBadgeSettings(singletons::GymBadgeSettingsEntry),
305    HapticsSettings(singletons::HapticsSettingsEntry),
306    IapSettings(singletons::IapSettingsEntry),
307    IbfcLightweightSettings(singletons::IbfcLightweightSettingsEntry),
308    ImpressionTrackingSettings(singletons::ImpressionTrackingSettingsEntry),
309    InAppSurveySettings(singletons::InAppSurveySettingsEntry),
310    IncidentPrioritySettings(singletons::IncidentPrioritySettingsEntry),
311    IncidentVisibilitySettings(singletons::IncidentVisibilitySettingsEntry),
312    InventorySettings(singletons::InventorySettingsEntry),
313    IrisSocialSettings(singletons::IrisSocialSettingsEntry),
314    IrisSocialUxFunnelSettings(singletons::IrisSocialUxFunnelSettingsEntry),
315    ItemCurrencyValues(singletons::ItemCurrencyValuesEntry),
316    ItemInventoryUpdateSettings(singletons::ItemInventoryUpdateSettingsEntry),
317    JoinRaidViaFriendListSettings(singletons::JoinRaidViaFriendListSettingsEntry),
318    LanguageSelectorSettings(singletons::LanguageSelectorSettingsEntry),
319    LuckyPokemonSettings(singletons::LuckyPokemonSettingsEntry),
320    MainMenuChanges(singletons::MainMenuChangesEntry),
321    MapDisplaySettings(singletons::MapDisplaySettingsEntry),
322    MapObjectsInteractionRangeSettings(singletons::MapObjectsInteractionRangeSettingsEntry),
323    MegaEvoSettings(singletons::MegaEvoSettingsEntry),
324    MonodepthSettings(singletons::MonodepthSettingsEntry),
325    MpSettings(singletons::MpSettingsEntry),
326    NaturalArtDayNightFeatureSettings(singletons::NaturalArtDayNightFeatureSettingsEntry),
327    NearbyPokemonSettings(singletons::NearbyPokemonSettingsEntry),
328    NeutralAvatarSettings(singletons::NeutralAvatarSettingsEntry),
329    OnboardingSettings(singletons::OnboardingSettingsEntry),
330    OptimizationsProto(singletons::OptimizationsProtoEntry),
331    PartyDarkLaunchSettings(singletons::PartyDarkLaunchSettingsEntry),
332    PartyIapBoostsSettings(singletons::PartyIapBoostsSettingsEntry),
333    PartyRecommendationSettings(singletons::PartyRecommendationSettingsEntry),
334    PhotoSettings(singletons::PhotoSettingsEntry),
335    PlannerSettings(singletons::PlannerSettingsEntry),
336    PlayerBonusSystemSettings(singletons::PlayerBonusSystemSettingsEntry),
337    PlayerLevel(singletons::PlayerLevelEntry),
338    PokeballThrowPropertySettings(singletons::PokeballThrowPropertySettingsEntry),
339    PokecoinPurchaseDisplayGmt(singletons::PokecoinPurchaseDisplayGmtEntry),
340    PokedexCategoriesSettings(singletons::PokedexCategoriesSettingsEntry),
341    PokedexSizeStatsSystemSettings(singletons::PokedexSizeStatsSystemSettingsEntry),
342    Pokedexv2featureFlags(singletons::Pokedexv2featureFlagsEntry),
343    PokedexV2settings(singletons::PokedexV2settingsEntry),
344    PokemonFxSettings(singletons::PokemonFxSettingsEntry),
345    PokemonHomeSettings(singletons::PokemonHomeSettingsEntry),
346    PokemonTagSettings(singletons::PokemonTagSettingsEntry),
347    PopupControlSettings(singletons::PopupControlSettingsEntry),
348    PostcardCollectionSettings(singletons::PostcardCollectionSettingsEntry),
349    PowerUpPokestopsSettings(singletons::PowerUpPokestopsSettingsEntry),
350    PrimalEvoSettings(singletons::PrimalEvoSettingsEntry),
351    PtcOauthSettings(singletons::PtcOauthSettingsEntry),
352    QuestDialogueInboxSettings(singletons::QuestDialogueInboxSettingsEntry),
353    QuickInviteSettings(singletons::QuickInviteSettingsEntry),
354    RaidEntryCostSettings(singletons::RaidEntryCostSettingsEntry),
355    RaidLobbyCounterSettings(singletons::RaidLobbyCounterSettingsEntry),
356    RaidSettings(singletons::RaidSettingsEntry),
357    ReferralSettings(singletons::ReferralSettingsEntry),
358    RemoteTradeSettings(singletons::RemoteTradeSettingsEntry),
359    RouteBadgeSettings(singletons::RouteBadgeSettingsEntry),
360    RouteCreationSettings(singletons::RouteCreationSettingsEntry),
361    RouteDiscoverySettings(singletons::RouteDiscoverySettingsEntry),
362    RoutePinSettings(singletons::RoutePinSettingsEntry),
363    RoutePlaySettings(singletons::RoutePlaySettingsEntry),
364    RoutesNearbyNotifSettings(singletons::RoutesNearbyNotifSettingsEntry),
365    RoutesPartyPlayInteropSettings(singletons::RoutesPartyPlayInteropSettingsEntry),
366    RouteStampCategorySettings(singletons::RouteStampCategorySettingsEntry),
367    SharedFusionSettings(singletons::SharedFusionSettingsEntry),
368    SharedMoveSettings(singletons::SharedMoveSettingsEntry),
369    SoftSfidaSettings(singletons::SoftSfidaSettingsEntry),
370    SourdoughMoveMappingSettings(singletons::SourdoughMoveMappingSettingsEntry),
371    SpecialEggSettings(singletons::SpecialEggSettingsEntry),
372    SponsoredGeofenceGiftSettings(singletons::SponsoredGeofenceGiftSettingsEntry),
373    SquashSettings(singletons::SquashSettingsEntry),
374    StampCollectionSettings(singletons::StampCollectionSettingsEntry),
375    StationedPokemonTableSettings(singletons::StationedPokemonTableSettingsEntry),
376    StickerCategorySettings(singletons::StickerCategorySettingsEntry),
377    StyleShopSettings(singletons::StyleShopSettingsEntry),
378    TicketGiftingSettings(singletons::TicketGiftingSettingsEntry),
379    TodayViewSettings(singletons::TodayViewSettingsEntry),
380    TutorialSettings(singletons::TutorialSettingsEntry),
381    UsernameSuggestionSettings(singletons::UsernameSuggestionSettingsEntry),
382    VerboseLogCombatSettings(singletons::VerboseLogCombatSettingsEntry),
383    VerboseLogRaidSettings(singletons::VerboseLogRaidSettingsEntry),
384    VistaGeneralSettings(singletons::VistaGeneralSettingsEntry),
385    VnextBattleConfig(singletons::VnextBattleConfigEntry),
386    VsSeekerClientSettings(singletons::VsSeekerClientSettingsEntry),
387    VsSeekerScheduleSettings(singletons::VsSeekerScheduleSettingsEntry),
388    WeatherBonusSettings(singletons::WeatherBonusSettingsEntry),
389}
390
391// O(1)-dispatch deserializer for MasterfileEntry. Avoids serde's untagged
392// fallback (which scans variants in declaration order, partially parsing
393// each before realizing the discriminator's wrong) by:
394//
395//   1. Materializing the entry once as a serde_json::Value.
396//   2. Inspecting `data`'s key set to find the non-templateId key — that's
397//      the discriminator that uniquely identifies the variant.
398//   3. For stubs (no payload key in data), falling back to `templateId`
399//      value as the dispatch key.
400//   4. Re-deserializing the captured Value into the chosen variant's
401//      Entry type via `from_value`.
402impl<'de> Deserialize<'de> for MasterfileEntry {
403    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
404    where
405        D: serde::Deserializer<'de>,
406    {
407        use serde::de::Error;
408        let value = serde_json::Value::deserialize(deserializer)?;
409        let discriminator = value
410            .get("data")
411            .and_then(|d| d.as_object())
412            .and_then(|m| m.keys().find(|k| k.as_str() != "templateId"))
413            .cloned();
414
415        let result: serde_json::Result<Self> = if let Some(disc) = discriminator.as_deref() {
416            match disc {
417                "pokemonExtendedSettings" => {
418                    serde_json::from_value(value).map(Self::PokemonExtendedSettings)
419                }
420                "genderSettings" => serde_json::from_value(value).map(Self::GenderSettings),
421                "pokemonSettings" => serde_json::from_value(value).map(Self::PokemonSettings),
422                "avatarCustomization" => {
423                    serde_json::from_value(value).map(Self::AvatarCustomization)
424                }
425                "avatarItemDisplay" => serde_json::from_value(value).map(Self::AvatarItemDisplay),
426                "iapItemDisplay" => serde_json::from_value(value).map(Self::IapItemDisplay),
427                "formSettings" => serde_json::from_value(value).map(Self::FormSettings),
428                "badgeSettings" => serde_json::from_value(value).map(Self::BadgeSettings),
429                "stickerMetadata" => serde_json::from_value(value).map(Self::StickerMetadata),
430                "pokemonFamily" => serde_json::from_value(value).map(Self::PokemonFamily),
431                "eventPassTierSettings" => {
432                    serde_json::from_value(value).map(Self::EventPassTierSettings)
433                }
434                "moveSettings" => serde_json::from_value(value).map(Self::MoveSettings),
435                "moveSequenceSettings" => {
436                    serde_json::from_value(value).map(Self::MoveSequenceSettings)
437                }
438                "combatMove" => serde_json::from_value(value).map(Self::CombatMove),
439                "settingsOverrideRule" => {
440                    serde_json::from_value(value).map(Self::SettingsOverrideRule)
441                }
442                "locationCardSettings" => {
443                    serde_json::from_value(value).map(Self::LocationCardSettings)
444                }
445                "itemSettings" => serde_json::from_value(value).map(Self::ItemSettings),
446                "combatLeague" => serde_json::from_value(value).map(Self::CombatLeague),
447                "megaEvoLevelSettings" => {
448                    serde_json::from_value(value).map(Self::MegaEvoLevelSettings)
449                }
450                "levelUpRewards" => serde_json::from_value(value).map(Self::LevelUpRewards),
451                "evolutionChainDisplaySettings" => {
452                    serde_json::from_value(value).map(Self::EvolutionChainDisplaySettings)
453                }
454                "invasionNpcDisplaySettings" => {
455                    serde_json::from_value(value).map(Self::InvasionNpcDisplaySettings)
456                }
457                "clientQuestTemplate" => {
458                    serde_json::from_value(value).map(Self::ClientQuestTemplate)
459                }
460                "temporaryEvolutionSettings" => {
461                    serde_json::from_value(value).map(Self::TemporaryEvolutionSettings)
462                }
463                "vsSeekerLoot" => serde_json::from_value(value).map(Self::VsSeekerLoot),
464                "photoSetsSettingsProto" => {
465                    serde_json::from_value(value).map(Self::PhotoSetsSettingsProto)
466                }
467                "evolutionQuestTemplate" => {
468                    serde_json::from_value(value).map(Self::EvolutionQuestTemplate)
469                }
470                "limitedPurchaseSkuSettings" => {
471                    serde_json::from_value(value).map(Self::LimitedPurchaseSkuSettings)
472                }
473                "combatRankingProtoSettings" => {
474                    serde_json::from_value(value).map(Self::CombatRankingProtoSettings)
475                }
476                "itemExpirationSettings" => {
477                    serde_json::from_value(value).map(Self::ItemExpirationSettings)
478                }
479                "combatType" => serde_json::from_value(value).map(Self::CombatType),
480                "typeEffective" => serde_json::from_value(value).map(Self::TypeEffective),
481                "iapCategoryDisplay" => serde_json::from_value(value).map(Self::IapCategoryDisplay),
482                "codeGateProto" => serde_json::from_value(value).map(Self::CodeGateProto),
483                "featureGate" => serde_json::from_value(value).map(Self::FeatureGate),
484                "recommendedSearchSettings" => {
485                    serde_json::from_value(value).map(Self::RecommendedSearchSettings)
486                }
487                "combatNpcTrainer" => serde_json::from_value(value).map(Self::CombatNpcTrainer),
488                "nonCombatMoveSettings" => {
489                    serde_json::from_value(value).map(Self::NonCombatMoveSettings)
490                }
491                "buddyActivityCategorySettings" => {
492                    serde_json::from_value(value).map(Self::BuddyActivityCategorySettings)
493                }
494                "breadMoveLevelSettings" => {
495                    serde_json::from_value(value).map(Self::BreadMoveLevelSettings)
496                }
497                "buddyEmotionLevelSettings" => {
498                    serde_json::from_value(value).map(Self::BuddyEmotionLevelSettings)
499                }
500                "pokemonHomeFormReversions" => {
501                    serde_json::from_value(value).map(Self::PokemonHomeFormReversions)
502                }
503                "pokestopInvasionAvailabilitySettings" => {
504                    serde_json::from_value(value).map(Self::PokestopInvasionAvailabilitySettings)
505                }
506                "weatherAffinities" => serde_json::from_value(value).map(Self::WeatherAffinities),
507                "friendshipMilestoneSettings" => {
508                    serde_json::from_value(value).map(Self::FriendshipMilestoneSettings)
509                }
510                "pokemonScaleSettings" => {
511                    serde_json::from_value(value).map(Self::PokemonScaleSettings)
512                }
513                "buddyLevelSettings" => serde_json::from_value(value).map(Self::BuddyLevelSettings),
514                "tappableSettings" => serde_json::from_value(value).map(Self::TappableSettings),
515                "fortPowerUpLevelSettings" => {
516                    serde_json::from_value(value).map(Self::FortPowerUpLevelSettings)
517                }
518                "pokemonHomeEnergyCosts" => {
519                    serde_json::from_value(value).map(Self::PokemonHomeEnergyCosts)
520                }
521                "combatNpcPersonality" => {
522                    serde_json::from_value(value).map(Self::CombatNpcPersonality)
523                }
524                "languageSettings" => serde_json::from_value(value).map(Self::LanguageSettings),
525                "questSettings" => serde_json::from_value(value).map(Self::QuestSettings),
526                "rollBack" => serde_json::from_value(value).map(Self::RollBack),
527                "avatarGroupOrderSettings" => {
528                    serde_json::from_value(value).map(Self::AvatarGroupOrderSettings)
529                }
530                "eventPassSettings" => serde_json::from_value(value).map(Self::EventPassSettings),
531                "partyPlayGeneralSettings" => {
532                    serde_json::from_value(value).map(Self::PartyPlayGeneralSettings)
533                }
534                "pokemonUpgrades" => serde_json::from_value(value).map(Self::PokemonUpgrades),
535                "vsSeekerPokemonRewards" => {
536                    serde_json::from_value(value).map(Self::VsSeekerPokemonRewards)
537                }
538                "accessibilitySettings" => {
539                    serde_json::from_value(value).map(Self::AccessibilitySettings)
540                }
541                "additiveSceneSettings" => {
542                    serde_json::from_value(value).map(Self::AdditiveSceneSettings)
543                }
544                "addressablePokemonSettings" => {
545                    serde_json::from_value(value).map(Self::AddressablePokemonSettings)
546                }
547                "addressBookImportSettings" => {
548                    serde_json::from_value(value).map(Self::AddressBookImportSettings)
549                }
550                "advancedSettings" => serde_json::from_value(value).map(Self::AdvancedSettings),
551                "arPhotoFeatureFlags" => {
552                    serde_json::from_value(value).map(Self::ArPhotoFeatureFlags)
553                }
554                "arTelemetrySettings" => {
555                    serde_json::from_value(value).map(Self::ArTelemetrySettings)
556                }
557                "assetRefreshProto" => serde_json::from_value(value).map(Self::AssetRefreshProto),
558                "avatarFeatureFlags" => serde_json::from_value(value).map(Self::AvatarFeatureFlags),
559                "avatarStoreFooterFlags" => {
560                    serde_json::from_value(value).map(Self::AvatarStoreFooterFlags)
561                }
562                "avatarStoreSubcategoryFilteringFlags" => {
563                    serde_json::from_value(value).map(Self::AvatarStoreSubcategoryFilteringFlags)
564                }
565                "backgroundModeSettings" => {
566                    serde_json::from_value(value).map(Self::BackgroundModeSettings)
567                }
568                "battleAnimationSettings" => {
569                    serde_json::from_value(value).map(Self::BattleAnimationSettings)
570                }
571                "battleHubBadgeSettings" => {
572                    serde_json::from_value(value).map(Self::BattleHubBadgeSettings)
573                }
574                "battleHubOrderSettings" => {
575                    serde_json::from_value(value).map(Self::BattleHubOrderSettings)
576                }
577                "battleInputBufferSettings" => {
578                    serde_json::from_value(value).map(Self::BattleInputBufferSettings)
579                }
580                "battlePartySettings" => {
581                    serde_json::from_value(value).map(Self::BattlePartySettings)
582                }
583                "battleSettings" => serde_json::from_value(value).map(Self::BattleSettings),
584                "battleVisualSettings" => {
585                    serde_json::from_value(value).map(Self::BattleVisualSettings)
586                }
587                "belugaPokemonWhitelist" => {
588                    serde_json::from_value(value).map(Self::BelugaPokemonWhitelist)
589                }
590                "bestFriendsPlusSettings" => {
591                    serde_json::from_value(value).map(Self::BestFriendsPlusSettings)
592                }
593                "breadBattleClientSettings" => {
594                    serde_json::from_value(value).map(Self::BreadBattleClientSettings)
595                }
596                "breadFeatureFlags" => serde_json::from_value(value).map(Self::BreadFeatureFlags),
597                "breadLobbyCounterSettings" => {
598                    serde_json::from_value(value).map(Self::BreadLobbyCounterSettings)
599                }
600                "breadLobbyUpdateSettings" => {
601                    serde_json::from_value(value).map(Self::BreadLobbyUpdateSettings)
602                }
603                "breadMoveMappings" => serde_json::from_value(value).map(Self::BreadMoveMappings),
604                "breadPokemonScalingSettings" => {
605                    serde_json::from_value(value).map(Self::BreadPokemonScalingSettings)
606                }
607                "breadSettings" => serde_json::from_value(value).map(Self::BreadSettings),
608                "buddyEncounterCameoSettings" => {
609                    serde_json::from_value(value).map(Self::BuddyEncounterCameoSettings)
610                }
611                "buddyHungerSettings" => {
612                    serde_json::from_value(value).map(Self::BuddyHungerSettings)
613                }
614                "buddyInteractionSettings" => {
615                    serde_json::from_value(value).map(Self::BuddyInteractionSettings)
616                }
617                "buddySwapSettings" => serde_json::from_value(value).map(Self::BuddySwapSettings),
618                "buddyWalkSettings" => serde_json::from_value(value).map(Self::BuddyWalkSettings),
619                "bulkHealingSettings" => {
620                    serde_json::from_value(value).map(Self::BulkHealingSettings)
621                }
622                "butterflyCollectorSettings" => {
623                    serde_json::from_value(value).map(Self::ButterflyCollectorSettings)
624                }
625                "campfireSettings" => serde_json::from_value(value).map(Self::CampfireSettings),
626                "catchRadiusMultiplierSettings" => {
627                    serde_json::from_value(value).map(Self::CatchRadiusMultiplierSettings)
628                }
629                "combatCompetitiveSeasonSettings" => {
630                    serde_json::from_value(value).map(Self::CombatCompetitiveSeasonSettings)
631                }
632                "combatLeagueSettings" => {
633                    serde_json::from_value(value).map(Self::CombatLeagueSettings)
634                }
635                "combatSettings" => serde_json::from_value(value).map(Self::CombatSettings),
636                "combatStatStageSettings" => {
637                    serde_json::from_value(value).map(Self::CombatStatStageSettings)
638                }
639                "contestSettings" => serde_json::from_value(value).map(Self::ContestSettings),
640                "conversationSettings" => {
641                    serde_json::from_value(value).map(Self::ConversationSettings)
642                }
643                "crossGameSocialSettings" => {
644                    serde_json::from_value(value).map(Self::CrossGameSocialSettings)
645                }
646                "dailyAdventureIncenseSettings" => {
647                    serde_json::from_value(value).map(Self::DailyAdventureIncenseSettings)
648                }
649                "deepLinkingSettings" => {
650                    serde_json::from_value(value).map(Self::DeepLinkingSettings)
651                }
652                "eggHatchImprovementsSettings" => {
653                    serde_json::from_value(value).map(Self::EggHatchImprovementsSettings)
654                }
655                "encounterSettings" => serde_json::from_value(value).map(Self::EncounterSettings),
656                "errorReportingSettings" => {
657                    serde_json::from_value(value).map(Self::ErrorReportingSettings)
658                }
659                "eventPlannerPopularNotificationSettings" => {
660                    serde_json::from_value(value).map(Self::EventPlannerPopularNotificationSettings)
661                }
662                "externalAddressableAssetsSettings" => {
663                    serde_json::from_value(value).map(Self::ExternalAddressableAssetsSettings)
664                }
665                "featureUnlockLevelSettings" => {
666                    serde_json::from_value(value).map(Self::FeatureUnlockLevelSettings)
667                }
668                "geotargetedQuestSettings" => {
669                    serde_json::from_value(value).map(Self::GeotargetedQuestSettings)
670                }
671                "giftingSettings" => serde_json::from_value(value).map(Self::GiftingSettings),
672                "guiSearchSettings" => serde_json::from_value(value).map(Self::GuiSearchSettings),
673                "gymBadgeSettings" => serde_json::from_value(value).map(Self::GymBadgeSettings),
674                "hapticsSettings" => serde_json::from_value(value).map(Self::HapticsSettings),
675                "iapSettings" => serde_json::from_value(value).map(Self::IapSettings),
676                "ibfcLightweightSettings" => {
677                    serde_json::from_value(value).map(Self::IbfcLightweightSettings)
678                }
679                "impressionTrackingSettings" => {
680                    serde_json::from_value(value).map(Self::ImpressionTrackingSettings)
681                }
682                "inAppSurveySettings" => {
683                    serde_json::from_value(value).map(Self::InAppSurveySettings)
684                }
685                "incidentPrioritySettings" => {
686                    serde_json::from_value(value).map(Self::IncidentPrioritySettings)
687                }
688                "incidentVisibilitySettings" => {
689                    serde_json::from_value(value).map(Self::IncidentVisibilitySettings)
690                }
691                "inventorySettings" => serde_json::from_value(value).map(Self::InventorySettings),
692                "irisSocialSettings" => serde_json::from_value(value).map(Self::IrisSocialSettings),
693                "irisSocialUxFunnelSettings" => {
694                    serde_json::from_value(value).map(Self::IrisSocialUxFunnelSettings)
695                }
696                "itemCurrencyValues" => serde_json::from_value(value).map(Self::ItemCurrencyValues),
697                "itemInventoryUpdateSettings" => {
698                    serde_json::from_value(value).map(Self::ItemInventoryUpdateSettings)
699                }
700                "joinRaidViaFriendListSettings" => {
701                    serde_json::from_value(value).map(Self::JoinRaidViaFriendListSettings)
702                }
703                "languageSelectorSettings" => {
704                    serde_json::from_value(value).map(Self::LanguageSelectorSettings)
705                }
706                "luckyPokemonSettings" => {
707                    serde_json::from_value(value).map(Self::LuckyPokemonSettings)
708                }
709                "mainMenuChanges" => serde_json::from_value(value).map(Self::MainMenuChanges),
710                "mapDisplaySettings" => serde_json::from_value(value).map(Self::MapDisplaySettings),
711                "mapObjectsInteractionRangeSettings" => {
712                    serde_json::from_value(value).map(Self::MapObjectsInteractionRangeSettings)
713                }
714                "megaEvoSettings" => serde_json::from_value(value).map(Self::MegaEvoSettings),
715                "monodepthSettings" => serde_json::from_value(value).map(Self::MonodepthSettings),
716                "mpSettings" => serde_json::from_value(value).map(Self::MpSettings),
717                "naturalArtDayNightFeatureSettings" => {
718                    serde_json::from_value(value).map(Self::NaturalArtDayNightFeatureSettings)
719                }
720                "nearbyPokemonSettings" => {
721                    serde_json::from_value(value).map(Self::NearbyPokemonSettings)
722                }
723                "neutralAvatarSettings" => {
724                    serde_json::from_value(value).map(Self::NeutralAvatarSettings)
725                }
726                "onboardingSettings" => serde_json::from_value(value).map(Self::OnboardingSettings),
727                "optimizationsProto" => serde_json::from_value(value).map(Self::OptimizationsProto),
728                "partyDarkLaunchSettings" => {
729                    serde_json::from_value(value).map(Self::PartyDarkLaunchSettings)
730                }
731                "partyIapBoostsSettings" => {
732                    serde_json::from_value(value).map(Self::PartyIapBoostsSettings)
733                }
734                "partyRecommendationSettings" => {
735                    serde_json::from_value(value).map(Self::PartyRecommendationSettings)
736                }
737                "photoSettings" => serde_json::from_value(value).map(Self::PhotoSettings),
738                "plannerSettings" => serde_json::from_value(value).map(Self::PlannerSettings),
739                "playerBonusSystemSettings" => {
740                    serde_json::from_value(value).map(Self::PlayerBonusSystemSettings)
741                }
742                "playerLevel" => serde_json::from_value(value).map(Self::PlayerLevel),
743                "pokeballThrowPropertySettings" => {
744                    serde_json::from_value(value).map(Self::PokeballThrowPropertySettings)
745                }
746                "pokecoinPurchaseDisplayGmt" => {
747                    serde_json::from_value(value).map(Self::PokecoinPurchaseDisplayGmt)
748                }
749                "pokedexCategoriesSettings" => {
750                    serde_json::from_value(value).map(Self::PokedexCategoriesSettings)
751                }
752                "pokedexSizeStatsSystemSettings" => {
753                    serde_json::from_value(value).map(Self::PokedexSizeStatsSystemSettings)
754                }
755                "pokedexv2FeatureFlags" => {
756                    serde_json::from_value(value).map(Self::Pokedexv2featureFlags)
757                }
758                "pokedexV2Settings" => serde_json::from_value(value).map(Self::PokedexV2settings),
759                "pokemonFxSettings" => serde_json::from_value(value).map(Self::PokemonFxSettings),
760                "pokemonHomeSettings" => {
761                    serde_json::from_value(value).map(Self::PokemonHomeSettings)
762                }
763                "pokemonTagSettings" => serde_json::from_value(value).map(Self::PokemonTagSettings),
764                "popupControlSettings" => {
765                    serde_json::from_value(value).map(Self::PopupControlSettings)
766                }
767                "postcardCollectionSettings" => {
768                    serde_json::from_value(value).map(Self::PostcardCollectionSettings)
769                }
770                "powerUpPokestopsSettings" => {
771                    serde_json::from_value(value).map(Self::PowerUpPokestopsSettings)
772                }
773                "primalEvoSettings" => serde_json::from_value(value).map(Self::PrimalEvoSettings),
774                "ptcOauthSettings" => serde_json::from_value(value).map(Self::PtcOauthSettings),
775                "quickInviteSettings" => {
776                    serde_json::from_value(value).map(Self::QuickInviteSettings)
777                }
778                "raidLobbyCounterSettings" => {
779                    serde_json::from_value(value).map(Self::RaidLobbyCounterSettings)
780                }
781                "raidSettings" => serde_json::from_value(value).map(Self::RaidSettings),
782                "referralSettings" => serde_json::from_value(value).map(Self::ReferralSettings),
783                "remoteTradeSettings" => {
784                    serde_json::from_value(value).map(Self::RemoteTradeSettings)
785                }
786                "routeBadgeSettings" => serde_json::from_value(value).map(Self::RouteBadgeSettings),
787                "routeCreationSettings" => {
788                    serde_json::from_value(value).map(Self::RouteCreationSettings)
789                }
790                "routeDiscoverySettings" => {
791                    serde_json::from_value(value).map(Self::RouteDiscoverySettings)
792                }
793                "routePinSettings" => serde_json::from_value(value).map(Self::RoutePinSettings),
794                "routePlaySettings" => serde_json::from_value(value).map(Self::RoutePlaySettings),
795                "routesNearbyNotifSettings" => {
796                    serde_json::from_value(value).map(Self::RoutesNearbyNotifSettings)
797                }
798                "routesPartyPlayInteropSettings" => {
799                    serde_json::from_value(value).map(Self::RoutesPartyPlayInteropSettings)
800                }
801                "routeStampCategorySettings" => {
802                    serde_json::from_value(value).map(Self::RouteStampCategorySettings)
803                }
804                "sharedFusionSettings" => {
805                    serde_json::from_value(value).map(Self::SharedFusionSettings)
806                }
807                "sharedMoveSettings" => serde_json::from_value(value).map(Self::SharedMoveSettings),
808                "sourdoughMoveMappingSettings" => {
809                    serde_json::from_value(value).map(Self::SourdoughMoveMappingSettings)
810                }
811                "specialEggSettings" => serde_json::from_value(value).map(Self::SpecialEggSettings),
812                "sponsoredGeofenceGiftSettings" => {
813                    serde_json::from_value(value).map(Self::SponsoredGeofenceGiftSettings)
814                }
815                "squashSettings" => serde_json::from_value(value).map(Self::SquashSettings),
816                "stampCollectionSettings" => {
817                    serde_json::from_value(value).map(Self::StampCollectionSettings)
818                }
819                "stationedPokemonTableSettings" => {
820                    serde_json::from_value(value).map(Self::StationedPokemonTableSettings)
821                }
822                "stickerCategorySettings" => {
823                    serde_json::from_value(value).map(Self::StickerCategorySettings)
824                }
825                "styleShopSettings" => serde_json::from_value(value).map(Self::StyleShopSettings),
826                "ticketGiftingSettings" => {
827                    serde_json::from_value(value).map(Self::TicketGiftingSettings)
828                }
829                "todayViewSettings" => serde_json::from_value(value).map(Self::TodayViewSettings),
830                "tutorialSettings" => serde_json::from_value(value).map(Self::TutorialSettings),
831                "usernameSuggestionSettings" => {
832                    serde_json::from_value(value).map(Self::UsernameSuggestionSettings)
833                }
834                "verboseLogCombatSettings" => {
835                    serde_json::from_value(value).map(Self::VerboseLogCombatSettings)
836                }
837                "verboseLogRaidSettings" => {
838                    serde_json::from_value(value).map(Self::VerboseLogRaidSettings)
839                }
840                "vistaGeneralSettings" => {
841                    serde_json::from_value(value).map(Self::VistaGeneralSettings)
842                }
843                "vnextBattleConfig" => serde_json::from_value(value).map(Self::VnextBattleConfig),
844                "vsSeekerClientSettings" => {
845                    serde_json::from_value(value).map(Self::VsSeekerClientSettings)
846                }
847                "vsSeekerScheduleSettings" => {
848                    serde_json::from_value(value).map(Self::VsSeekerScheduleSettings)
849                }
850                "weatherBonusSettings" => {
851                    serde_json::from_value(value).map(Self::WeatherBonusSettings)
852                }
853                other => Err(serde_json::Error::custom(format!(
854                    "unknown discriminator: {}",
855                    other
856                ))),
857            }
858        } else {
859            let template_id = value
860                .get("templateId")
861                .and_then(|t| t.as_str())
862                .map(String::from);
863            match template_id.as_deref() {
864                Some("AMUSE_BOUCHE_WELCOME_BACK_REWARDS") => {
865                    serde_json::from_value(value).map(Self::AmuseBoucheWelcomeBackRewards)
866                }
867                Some("EVENT_SERVER_SETTINGS") => {
868                    serde_json::from_value(value).map(Self::EventServerSettings)
869                }
870                Some("QUEST_DIALOGUE_INBOX_SETTINGS") => {
871                    serde_json::from_value(value).map(Self::QuestDialogueInboxSettings)
872                }
873                Some("RAID_ENTRY_COST_SETTINGS") => {
874                    serde_json::from_value(value).map(Self::RaidEntryCostSettings)
875                }
876                Some("SOFT_SFIDA_SETTINGS") => {
877                    serde_json::from_value(value).map(Self::SoftSfidaSettings)
878                }
879                Some(other) => Err(serde_json::Error::custom(format!(
880                    "unknown stub templateId: {}",
881                    other
882                ))),
883                None => Err(serde_json::Error::custom("stub entry missing templateId")),
884            }
885        };
886
887        result.map_err(D::Error::custom)
888    }
889}
890
891/// Parse a masterfile JSON string into a vector of typed entries.
892///
893/// # Errors
894///
895/// Returns the underlying [`serde_json::Error`] on malformed JSON or on a
896/// JSON entry that doesn't match any [`MasterfileEntry`] variant.
897///
898/// # Example
899///
900/// ```no_run
901/// let json = std::fs::read_to_string("masterfile.json").unwrap();
902/// let entries = pogo_masterfile_types::parse_masterfile(&json).unwrap();
903/// println!("{} entries", entries.len());
904/// ```
905pub fn parse_masterfile(json: &str) -> serde_json::Result<Vec<MasterfileEntry>> {
906    serde_json::from_str(json)
907}
908
909#[cfg(feature = "deprecated")]
910pub mod deprecated;