1use std::fmt;
2use std::str::FromStr;
3
4use crate::{Error, Result};
5
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct Id(String);
8
9impl Id {
10 pub fn new(value: impl Into<String>) -> Result<Self> {
11 let value = value.into();
12 if value.is_empty() {
13 return Err(Error::EmptyId);
14 }
15
16 Ok(Self(value))
17 }
18
19 pub fn as_str(&self) -> &str {
20 &self.0
21 }
22}
23
24impl fmt::Display for Id {
25 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
26 formatter.write_str(self.as_str())
27 }
28}
29
30impl FromStr for Id {
31 type Err = Error;
32
33 fn from_str(value: &str) -> Result<Self> {
34 Self::new(value)
35 }
36}
37
38macro_rules! typed_id {
39 ($name:ident) => {
40 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
41 pub struct $name(Id);
42
43 impl $name {
44 pub fn new(value: impl Into<String>) -> Result<Self> {
45 Id::new(value).map(Self)
46 }
47
48 pub fn as_str(&self) -> &str {
49 self.0.as_str()
50 }
51 }
52
53 impl fmt::Display for $name {
54 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
55 formatter.write_str(self.as_str())
56 }
57 }
58
59 impl FromStr for $name {
60 type Err = Error;
61
62 fn from_str(value: &str) -> Result<Self> {
63 Self::new(value)
64 }
65 }
66 };
67}
68
69typed_id!(ParameterId);
70typed_id!(PartId);
71typed_id!(DrawableId);