use serde::{Deserialize, Serialize};
use systemprompt_identifiers::{ApiKeyId, ScopeDimension};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AttributionSource {
Header,
ApiKey,
Default,
}
impl AttributionSource {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Header => "header",
Self::ApiKey => "api_key",
Self::Default => "default",
}
}
#[must_use]
pub fn parse(value: &str) -> Option<Self> {
match value {
"header" => Some(Self::Header),
"api_key" => Some(Self::ApiKey),
"default" => Some(Self::Default),
_ => None,
}
}
}
impl std::fmt::Display for AttributionSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AttributionEntry {
pub dimension: ScopeDimension,
pub value: String,
pub source: AttributionSource,
}
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct RequestAttribution {
pub entries: Vec<AttributionEntry>,
pub api_key_id: Option<ApiKeyId>,
}
impl RequestAttribution {
#[must_use]
pub fn none() -> Self {
Self::default()
}
#[must_use]
pub fn value_for(&self, dimension: &str) -> Option<&str> {
self.entries
.iter()
.find(|entry| entry.dimension.as_str() == dimension)
.map(|entry| entry.value.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ScopeBinding {
pub dimension: ScopeDimension,
pub value: String,
}