use std::fmt;
use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
use serde::{Deserialize, Serialize};
use crate::SourceError;
#[derive(
Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, JsonSchema,
)]
#[serde(transparent)]
pub struct NativeId(pub String);
impl NativeId {
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl From<&str> for NativeId {
fn from(value: &str) -> Self {
Self(value.to_owned())
}
}
impl From<String> for NativeId {
fn from(value: String) -> Self {
Self(value)
}
}
impl fmt::Display for NativeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
pub const SOURCE_NAME_PATTERN: &str = "^[a-z0-9][a-z0-9-]*$";
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(try_from = "String", into = "String")]
pub struct SourceName(String);
impl SourceName {
pub fn new(value: impl Into<String>) -> Result<Self, SourceError> {
let value = value.into();
if Self::is_valid(&value) {
Ok(Self(value))
} else {
Err(SourceError::Config {
message: format!(
"source name {value:?} is not usable; names must match {SOURCE_NAME_PATTERN} \
(lower-case letters, digits and hyphens, starting with a letter or digit)"
),
})
}
}
fn is_valid(value: &str) -> bool {
let mut chars = value.chars();
let Some(first) = chars.next() else {
return false;
};
if !(first.is_ascii_lowercase() || first.is_ascii_digit()) {
return false;
}
chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl TryFrom<String> for SourceName {
type Error = SourceError;
fn try_from(value: String) -> Result<Self, Self::Error> {
Self::new(value)
}
}
impl From<SourceName> for String {
fn from(value: SourceName) -> Self {
value.0
}
}
impl fmt::Display for SourceName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl JsonSchema for SourceName {
fn schema_name() -> std::borrow::Cow<'static, str> {
"SourceName".into()
}
fn json_schema(_generator: &mut SchemaGenerator) -> Schema {
json_schema!({
"type": "string",
"pattern": SOURCE_NAME_PATTERN,
"description": "The name a configuration document gives one configured source.",
})
}
}