1use std::{fmt::{Display, Formatter}, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4
5pub type Id = NonEmptyString;
6pub type Name = NonEmptyString;
7
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
10pub struct NonEmptyString(String);
11
12impl NonEmptyString {
13 pub fn as_str(&self) -> &str {
14 self.0.as_str()
15 }
16}
17
18impl Default for NonEmptyString {
19 fn default() -> Self {
20 NonEmptyString("00000000-0000-0000-0000-000000000000".to_owned())
21 }
22}
23
24impl From<NonEmptyString> for String {
25 fn from(id: NonEmptyString) -> Self {
26 id.0
27 }
28}
29impl TryFrom<String> for NonEmptyString {
30 type Error = crate::Error;
31
32 fn try_from(value: String) -> Result<Self, Self::Error> {
33 if value.is_empty() {
34 return Err(crate::Error::EmptyString("id"))
35 }
36 Ok(Self(value))
37 }
38}
39
40impl TryFrom<&str> for NonEmptyString {
41 type Error = crate::Error;
42
43 fn try_from(value: &str) -> Result<Self, Self::Error> {
44 if value.is_empty() {
45 return Err(crate::Error::EmptyString("id"))
46 }
47 Ok(Self(value.to_owned()))
48 }
49}
50
51impl FromStr for NonEmptyString {
52 type Err = crate::Error;
53
54 fn from_str(s: &str) -> Result<Self, Self::Err> {
55 Self::try_from(s)
56 }
57}
58
59impl Display for NonEmptyString {
60 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61 write!(f, "{}", self.0)
62 }
63}
64
65impl From<&NonEmptyString> for String {
66 fn from(id: &NonEmptyString) -> Self {
67 id.0.clone()
68 }
69}
70
71impl AsRef<str> for NonEmptyString {
72 fn as_ref(&self) -> &str {
73 &self.0
74 }
75}
76
77#[cfg(feature = "testkit")]
78impl<> proptest::arbitrary::Arbitrary for NonEmptyString {
79 type Parameters = ();
80 type Strategy = proptest::strategy::BoxedStrategy<Self>;
81
82 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
83 use proptest::prelude::*;
84 "\\PC+".prop_map(|id|
85 id.try_into().expect("generate valid id")
86 ).boxed()
87 }
88}