use std::str::FromStr;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum StorageKind {
File,
Sqlite,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub(crate) enum Client {
Claude,
Codex,
Crush,
Gemini,
Goose,
Opencode,
Pi,
}
impl Client {
pub(crate) const ALL: [Self; 7] = [
Self::Claude,
Self::Codex,
Self::Crush,
Self::Gemini,
Self::Goose,
Self::Opencode,
Self::Pi,
];
#[must_use]
pub(crate) const fn as_str(self) -> &'static str {
match self {
Self::Claude => "claude",
Self::Codex => "codex",
Self::Crush => "crush",
Self::Gemini => "gemini",
Self::Goose => "goose",
Self::Opencode => "opencode",
Self::Pi => "pi",
}
}
#[must_use]
pub(crate) const fn storage(self) -> StorageKind {
match self {
Self::Claude | Self::Codex | Self::Gemini | Self::Pi => StorageKind::File,
Self::Crush | Self::Goose | Self::Opencode => StorageKind::Sqlite,
}
}
}
impl std::fmt::Display for Client {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl AsRef<str> for Client {
fn as_ref(&self) -> &str {
self.as_str()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct ParseClientError;
impl std::fmt::Display for ParseClientError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"provider must be one of: {}",
Client::ALL.map(Client::as_str).join(", ")
)
}
}
impl std::error::Error for ParseClientError {}
impl FromStr for Client {
type Err = ParseClientError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
Self::ALL
.into_iter()
.find(|client| client.as_str() == value)
.ok_or(ParseClientError)
}
}