use super::content::ChatMessage;
use super::content::present_nullable;
use super::tools::{ChatTool, ToolChoice};
use crate::{Rest, WireRequest};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct GenerateContentRequestBody {
pub messages: Vec<ChatMessage>,
pub model: String,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub audio: Option<Option<ChatAudioParam>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub frequency_penalty: Option<Option<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub function_call: Option<FunctionCallChoice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub functions: Option<Vec<LegacyFunction>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub logit_bias: Option<Option<BTreeMap<String, f64>>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub logprobs: Option<Option<bool>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub max_completion_tokens: Option<Option<i64>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub max_tokens: Option<Option<i64>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub metadata: Option<Option<BTreeMap<String, String>>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub modalities: Option<Option<Vec<Modality>>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub moderation: Option<Option<Moderation>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub n: Option<Option<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parallel_tool_calls: Option<bool>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub prediction: Option<Option<Prediction>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub presence_penalty: Option<Option<f64>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub prompt_cache_key: Option<Option<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt_cache_options: Option<PromptCacheOptions>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub prompt_cache_retention: Option<Option<PromptCacheRetention>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub reasoning_effort: Option<Option<ReasoningEffort>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_format: Option<ResponseFormat>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub safety_identifier: Option<Option<String>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub seed: Option<Option<i64>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub service_tier: Option<Option<ServiceTier>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub stop: Option<Option<Stop>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub store: Option<Option<bool>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub stream: Option<Option<bool>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub stream_options: Option<Option<StreamOptions>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub temperature: Option<Option<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_choice: Option<ToolChoice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tools: Option<Vec<ChatTool>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub top_logprobs: Option<Option<i64>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub top_p: Option<Option<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user: Option<String>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub verbosity: Option<Option<Verbosity>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub web_search_options: Option<WebSearchOptions>,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
pub type GenerateContentRequest = WireRequest<GenerateContentRequestBody>;
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct ChatAudioParam {
pub voice: AudioVoice,
pub format: ChatAudioFormat,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum AudioVoice {
Name(AudioVoiceName),
Custom(CustomVoice),
String(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum AudioVoiceName {
#[serde(rename = "alloy")]
Alloy,
#[serde(rename = "ash")]
Ash,
#[serde(rename = "ballad")]
Ballad,
#[serde(rename = "coral")]
Coral,
#[serde(rename = "echo")]
Echo,
#[serde(rename = "fable")]
Fable,
#[serde(rename = "nova")]
Nova,
#[serde(rename = "onyx")]
Onyx,
#[serde(rename = "sage")]
Sage,
#[serde(rename = "shimmer")]
Shimmer,
#[serde(rename = "verse")]
Verse,
#[serde(rename = "marin")]
Marin,
#[serde(rename = "cedar")]
Cedar,
}
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct CustomVoice {
pub id: String,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum ChatAudioFormat {
#[serde(rename = "wav")]
Wav,
#[serde(rename = "aac")]
Aac,
#[serde(rename = "mp3")]
Mp3,
#[serde(rename = "flac")]
Flac,
#[serde(rename = "opus")]
Opus,
#[serde(rename = "pcm16")]
Pcm16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum Modality {
#[serde(rename = "text")]
Text,
#[serde(rename = "audio")]
Audio,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum FunctionCallMode {
#[serde(rename = "none")]
None,
#[serde(rename = "auto")]
Auto,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum FunctionCallChoice {
Mode(FunctionCallMode),
Name(LegacyFunctionChoice),
}
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct LegacyFunctionChoice {
pub name: String,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct LegacyFunction {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<Rest>,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct Moderation {
pub model: String,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub policy: Option<Option<ModerationPolicy>>,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct ModerationPolicy {
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub input: Option<Option<ModerationMode>>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub output: Option<Option<ModerationMode>>,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct ModerationMode {
pub mode: ModerationModeType,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum ModerationModeType {
#[serde(rename = "score")]
Score,
#[serde(rename = "block")]
Block,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct Prediction {
#[serde(rename = "type")]
pub type_: PredictionType,
pub content: super::content::TextContent,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum PredictionType {
#[serde(rename = "content")]
Content,
}
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct PromptCacheOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<PromptCacheOptionMode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ttl: Option<PromptCacheTtl>,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum PromptCacheOptionMode {
#[serde(rename = "implicit")]
Implicit,
#[serde(rename = "explicit")]
Explicit,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum PromptCacheTtl {
#[serde(rename = "30m")]
ThirtyMinutes,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum PromptCacheRetention {
#[serde(rename = "in_memory")]
InMemory,
#[serde(rename = "24h")]
TwentyFourHours,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum ReasoningEffort {
#[serde(rename = "none")]
None,
#[serde(rename = "minimal")]
Minimal,
#[serde(rename = "low")]
Low,
#[serde(rename = "medium")]
Medium,
#[serde(rename = "high")]
High,
#[serde(rename = "xhigh")]
XHigh,
#[serde(rename = "max")]
Max,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum ResponseFormat {
Text(TextResponseFormat),
JsonSchema(JsonSchemaResponseFormat),
JsonObject(JsonObjectResponseFormat),
}
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct TextResponseFormat {
#[serde(rename = "type")]
pub type_: TextResponseType,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum TextResponseType {
#[serde(rename = "text")]
Text,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct JsonSchemaResponseFormat {
#[serde(rename = "type")]
pub type_: JsonSchemaResponseType,
pub json_schema: JsonSchemaFormat,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum JsonSchemaResponseType {
#[serde(rename = "json_schema")]
JsonSchema,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct JsonSchemaFormat {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub schema: Option<Rest>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub strict: Option<Option<bool>>,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct JsonObjectResponseFormat {
#[serde(rename = "type")]
pub type_: JsonObjectResponseType,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum JsonObjectResponseType {
#[serde(rename = "json_object")]
JsonObject,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum ServiceTier {
#[serde(rename = "auto")]
Auto,
#[serde(rename = "default")]
Default,
#[serde(rename = "flex")]
Flex,
#[serde(rename = "scale")]
Scale,
#[serde(rename = "priority")]
Priority,
#[serde(rename = "fast")]
Fast,
#[serde(rename = "ultrafast")]
Ultrafast,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum Stop {
String(String),
Sequences(Vec<String>),
}
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct StreamOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub include_obfuscation: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub include_usage: Option<bool>,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum Verbosity {
#[serde(rename = "low")]
Low,
#[serde(rename = "medium")]
Medium,
#[serde(rename = "high")]
High,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct WebSearchOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub search_context_size: Option<SearchContextSize>,
#[serde(
default,
deserialize_with = "present_nullable",
skip_serializing_if = "Option::is_none"
)]
pub user_location: Option<Option<UserLocation>>,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum SearchContextSize {
#[serde(rename = "low")]
Low,
#[serde(rename = "medium")]
Medium,
#[serde(rename = "high")]
High,
}
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct UserLocation {
#[serde(rename = "type")]
pub type_: UserLocationType,
pub approximate: ApproximateLocation,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub enum UserLocationType {
#[serde(rename = "approximate")]
Approximate,
}
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
#[derive(gproxy_protocol_macros::DeclaredFields)]
pub struct ApproximateLocation {
#[serde(skip_serializing_if = "Option::is_none")]
pub city: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub country: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub region: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timezone: Option<String>,
#[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
pub rest: Rest,
}