use std::borrow::Cow;
use std::fmt;
use serde::de::Error as _;
use serde::{Deserialize, Deserializer, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
#[serde(transparent)]
pub struct ToolProfile(Cow<'static, str>);
impl ToolProfile {
pub const fn new(name: &'static str) -> Self {
assert!(!name.is_empty(), "tool profile name must not be empty");
Self(Cow::Borrowed(name))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for ToolProfile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl<'de> Deserialize<'de> for ToolProfile {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let name = String::deserialize(deserializer)?;
if name.is_empty() {
return Err(D::Error::custom("tool profile name must not be empty"));
}
Ok(Self(Cow::Owned(name)))
}
}
#[cfg(test)]
mod tests {
use serde_json::{from_value, json, to_value};
use super::*;
const BUG: ToolProfile = ToolProfile::new("bug");
#[test]
fn serializes_as_its_name() {
assert_eq!(to_value(BUG).unwrap(), json!("bug"));
}
#[test]
fn deserialized_profile_equals_the_constant() {
let back: ToolProfile = from_value(json!("bug")).unwrap();
assert_eq!(back, BUG);
}
#[test]
fn empty_name_is_rejected_on_deserialize() {
let err = from_value::<ToolProfile>(json!("")).unwrap_err();
assert_eq!(err.to_string(), "tool profile name must not be empty");
}
#[test]
fn unicode_name_is_kept_verbatim() {
let profile = ToolProfile::new("débogage");
assert_eq!(profile.as_str(), "débogage");
assert_eq!(to_value(&profile).unwrap(), json!("débogage"));
}
}