use super::validate_identity;
use crate::error::ModelError;
pub const SLOT_MAX_LEN: usize = 64;
arc_str_newtype! {
#[cfg_attr(feature = "schema", schemars(schema_with = "crate::schema::slot"))]
pub struct Slot;
}
impl Slot {
pub fn validate_format(&self) -> Result<(), ModelError> {
validate_identity("slot", self.as_str(), SLOT_MAX_LEN)
}
}
#[cfg(test)]
mod tests {
use super::Slot;
use std::sync::Arc;
#[test]
fn exposes_string_conversions_and_shares_clones() {
let slot = Slot::new("shared").unwrap();
let parsed: Slot = "shared".parse().unwrap();
assert_eq!(slot.as_str(), "shared");
assert_eq!(format!("{slot}"), "shared");
assert_eq!(slot, *"shared");
assert_eq!(slot, parsed);
let cloned = slot.clone();
let a: Arc<str> = slot.into_inner();
let b: Arc<str> = cloned.into_inner();
assert_eq!(&*a, "shared");
assert!(Arc::ptr_eq(&a, &b));
}
#[test]
fn serde_is_transparent() {
let slot = Slot::new("build").unwrap();
let json = serde_json::to_string(&slot).unwrap();
assert_eq!(json, "\"build\"");
assert_eq!(serde_json::from_str::<Slot>(&json).unwrap(), slot);
}
#[test]
fn validation_accepts_safe_values_and_rejects_unsafe_values() {
for valid in ["build.frontend", "build", "a"] {
Slot::new(valid).unwrap();
}
for invalid in ["build/frontend", "é", "with space", "a\nb", ".", ""] {
assert!(Slot::new(invalid).is_err(), "must reject {invalid:?}");
}
}
}