1use alpha2_media::IdError;
4use serde::{Deserialize, Deserializer, Serialize, de::Error as _};
5use std::fmt;
6
7macro_rules! define_id {
10 ($name:ident, $description:literal $(, without = $forbidden:literal, pattern = $pattern:literal)?) => {
11 #[doc = $description]
12 #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
13 #[serde(transparent)]
14 pub struct $name(String);
15
16 impl<'de> Deserialize<'de> for $name {
17 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
18 where
19 D: Deserializer<'de>,
20 {
21 let value = String::deserialize(deserializer)?;
22 $(if value.contains($forbidden) {
23 return Err(D::Error::custom(format!(
24 "{} {value:?} has a `{}`",
25 stringify!($name),
26 $forbidden
27 )));
28 })?
29 Self::new(value).map_err(D::Error::custom)
30 }
31 }
32
33 impl $name {
34 pub fn new(value: impl Into<String>) -> Result<Self, IdError> {
40 let value = value.into();
41 if value.is_empty() {
42 Err(IdError::Empty)
43 } else {
44 Ok(Self(value))
45 }
46 }
47
48 #[must_use]
50 pub fn as_str(&self) -> &str {
51 &self.0
52 }
53 }
54
55 #[cfg(feature = "schema")]
56 impl schemars::JsonSchema for $name {
57 fn schema_name() -> std::borrow::Cow<'static, str> {
58 stringify!($name).into()
59 }
60
61 fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
62 #[allow(unused_mut)]
63 let mut schema = schemars::json_schema!({
64 "description": $description,
65 "type": "string",
66 "minLength": 1,
67 });
68 $(schema.insert("pattern".into(), $pattern.into());)?
69 schema
70 }
71 }
72
73 impl fmt::Display for $name {
74 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
75 formatter.write_str(&self.0)
76 }
77 }
78 };
79}
80
81define_id!(ProjectId, "A stable project identifier.");
82define_id!(EffectResourceId, "A stable effect-resource identifier.");
83define_id!(TrackId, "A stable timeline-track identifier.");
84define_id!(ClipId, "A stable timeline-clip identifier.");
85define_id!(CompositionId, "A stable composition-graph identifier.");
86define_id!(
87 NodeId,
88 "A stable identifier of a node within one composition graph. It has no `/`, which joins the IDs of the group and media nodes a step was drawn through.",
89 without = '/',
90 pattern = "^[^/]*$"
91);