use std::fmt;
use std::str::FromStr;
use crate::KitError;
pub use crate::agent::AgentInfo;
#[derive(Clone, Copy)]
enum IdentityKind {
Agent,
Workspace,
Conversation,
Notification,
}
impl IdentityKind {
fn prefix(self) -> &'static str {
match self {
Self::Agent => "agent_",
Self::Workspace => "workspace_",
Self::Conversation => "conversation_",
Self::Notification => "notification_",
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
struct Identity {
canonical: String,
}
impl Identity {
fn new(kind: IdentityKind) -> Self {
Self {
canonical: format!("{}{}", kind.prefix(), uuid::Uuid::new_v4().simple()),
}
}
fn parse(kind: IdentityKind, value: String) -> Result<Self, KitError> {
let payload = value
.strip_prefix(kind.prefix())
.ok_or_else(|| KitError::invalid_input("Kit identity category is invalid"))?;
if payload.len() != 32
|| !payload
.bytes()
.all(|byte| byte.is_ascii_digit() || matches!(byte, b'a'..=b'f'))
{
return Err(KitError::invalid_input(
"Kit identity canonical form is invalid",
));
}
let parsed = uuid::Uuid::parse_str(payload)
.map_err(|_| KitError::invalid_input("Kit identity canonical form is invalid"))?;
if parsed.simple().to_string() != payload {
return Err(KitError::invalid_input(
"Kit identity canonical form is invalid",
));
}
Ok(Self { canonical: value })
}
fn as_str(&self) -> &str {
&self.canonical
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AgentId(Identity);
impl AgentId {
pub(crate) fn new() -> Self {
Self(Identity::new(IdentityKind::Agent))
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl fmt::Display for AgentId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
impl FromStr for AgentId {
type Err = KitError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
Identity::parse(IdentityKind::Agent, value.to_owned()).map(Self)
}
}
impl serde::Serialize for AgentId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> serde::Deserialize<'de> for AgentId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = <String as serde::Deserialize>::deserialize(deserializer)?;
Self::from_str(&value).map_err(serde::de::Error::custom)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct WorkspaceId(Identity);
impl WorkspaceId {
pub(crate) fn new() -> Self {
Self(Identity::new(IdentityKind::Workspace))
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl fmt::Display for WorkspaceId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
impl FromStr for WorkspaceId {
type Err = KitError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
Identity::parse(IdentityKind::Workspace, value.to_owned()).map(Self)
}
}
impl serde::Serialize for WorkspaceId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> serde::Deserialize<'de> for WorkspaceId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = <String as serde::Deserialize>::deserialize(deserializer)?;
Self::from_str(&value).map_err(serde::de::Error::custom)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ConversationId(Identity);
impl ConversationId {
pub(crate) fn new() -> Self {
Self(Identity::new(IdentityKind::Conversation))
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl fmt::Display for ConversationId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
impl FromStr for ConversationId {
type Err = KitError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
Identity::parse(IdentityKind::Conversation, value.to_owned()).map(Self)
}
}
impl serde::Serialize for ConversationId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> serde::Deserialize<'de> for ConversationId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = <String as serde::Deserialize>::deserialize(deserializer)?;
Self::from_str(&value).map_err(serde::de::Error::custom)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NotificationId(Identity);
impl NotificationId {
pub(crate) fn new() -> Self {
Self(Identity::new(IdentityKind::Notification))
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl fmt::Display for NotificationId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
impl FromStr for NotificationId {
type Err = KitError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
Identity::parse(IdentityKind::Notification, value.to_owned()).map(Self)
}
}
impl serde::Serialize for NotificationId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> serde::Deserialize<'de> for NotificationId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = <String as serde::Deserialize>::deserialize(deserializer)?;
Self::from_str(&value).map_err(serde::de::Error::custom)
}
}