use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::SourceError;
#[derive(
Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, JsonSchema,
)]
#[serde(try_from = "String", into = "String")]
pub struct MetadataKey(String);
impl MetadataKey {
pub const RESERVED_NAMESPACE: &'static str = "onetaskgraph";
pub fn new(key: impl Into<String>) -> Result<Self, String> {
let key = key.into();
let segments: Vec<&str> = key.split('.').collect();
if segments.len() < 2 {
return Err(format!(
"the metadata key {key:?} has no namespace: a key is `<namespace>.<name>`, two \
or more non-empty segments separated by dots; next: name it under a namespace \
of your own, such as `myapp.{key}`"
));
}
if segments.iter().any(|segment| segment.is_empty()) {
return Err(format!(
"the metadata key {key:?} has an empty segment: a key is `<namespace>.<name>`, \
two or more non-empty segments separated by dots; next: remove the extra dot"
));
}
if segments[0] == Self::RESERVED_NAMESPACE {
return Err(format!(
"the metadata key {key:?} is in the `{}.` namespace, which this product owns \
and keeps in step itself; next: name the key under a namespace of your own",
Self::RESERVED_NAMESPACE
));
}
Ok(Self(key))
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl TryFrom<String> for MetadataKey {
type Error = String;
fn try_from(key: String) -> Result<Self, Self::Error> {
Self::new(key)
}
}
impl From<MetadataKey> for String {
fn from(key: MetadataKey) -> Self {
key.0
}
}
impl std::fmt::Display for MetadataKey {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(formatter)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MetadataRecord {
Task,
Project,
Document,
}
impl MetadataRecord {
#[must_use]
pub const fn noun(self) -> &'static str {
match self {
Self::Task => "task",
Self::Project => "project",
Self::Document => "document",
}
}
}
impl std::fmt::Display for MetadataRecord {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str(self.noun())
}
}
#[must_use]
pub fn unwritable_metadata(kind: &str, record: MetadataRecord) -> SourceError {
SourceError::Refused {
message: format!("the {kind} plugin cannot write a {record}'s metadata on its own"),
}
}