systemprompt_identifiers/
quota.rs1use std::fmt;
12use std::str::FromStr;
13
14use serde::de::Error as _;
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16
17use crate::ScopeDimension;
18use crate::error::IdValidationError;
19
20#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
21pub enum QuotaSubjectKind {
22 #[default]
23 User,
24 ApiKey,
25 Dimension(ScopeDimension),
26}
27
28impl QuotaSubjectKind {
29 #[must_use]
30 pub fn as_str(&self) -> &str {
31 match self {
32 Self::User => "user",
33 Self::ApiKey => "api_key",
34 Self::Dimension(name) => name.as_str(),
35 }
36 }
37
38 #[must_use]
39 pub const fn is_principal(&self) -> bool {
40 matches!(self, Self::User | Self::ApiKey)
41 }
42}
43
44impl fmt::Display for QuotaSubjectKind {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 f.write_str(self.as_str())
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
51#[error("quota subject kind is neither a principal nor a scope dimension: {0}")]
52pub struct InvalidQuotaSubjectKind(#[from] IdValidationError);
53
54impl FromStr for QuotaSubjectKind {
55 type Err = InvalidQuotaSubjectKind;
56
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 match s {
59 "user" => Ok(Self::User),
60 "api_key" => Ok(Self::ApiKey),
61 other => Ok(Self::Dimension(ScopeDimension::try_new(other)?)),
62 }
63 }
64}
65
66impl Serialize for QuotaSubjectKind {
67 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
68 serializer.serialize_str(self.as_str())
69 }
70}
71
72impl<'de> Deserialize<'de> for QuotaSubjectKind {
73 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
74 let raw = String::deserialize(deserializer)?;
75 raw.parse().map_err(D::Error::custom)
76 }
77}