nodedb_types/id/
collection.rs1use std::fmt;
6
7use serde::{Deserialize, Serialize};
8
9use super::error::{IdError, validate};
10
11#[derive(
13 Debug,
14 Clone,
15 PartialEq,
16 Eq,
17 Hash,
18 Serialize,
19 Deserialize,
20 rkyv::Archive,
21 rkyv::Serialize,
22 rkyv::Deserialize,
23)]
24pub struct CollectionId(String);
25
26impl CollectionId {
27 pub fn try_new(id: impl Into<String>) -> Result<Self, IdError> {
32 let s = id.into();
33 validate(&s)?;
34 Ok(Self(s))
35 }
36
37 pub fn from_validated(id: String) -> Self {
41 Self(id)
42 }
43
44 pub fn as_str(&self) -> &str {
45 &self.0
46 }
47}
48
49impl fmt::Display for CollectionId {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 f.write_str(&self.0)
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::super::error::ID_MAX_LEN;
58 use super::*;
59
60 #[test]
61 fn try_new_accepts_valid() {
62 let c = CollectionId::try_new("embeddings").expect("valid");
63 assert_eq!(c.as_str(), "embeddings");
64 assert_eq!(c.to_string(), "embeddings");
65 }
66
67 #[test]
68 fn try_new_rejects_empty() {
69 assert_eq!(CollectionId::try_new(""), Err(IdError::Empty));
70 }
71
72 #[test]
73 fn try_new_rejects_too_long() {
74 let long = "x".repeat(ID_MAX_LEN + 1);
75 assert!(matches!(
76 CollectionId::try_new(long),
77 Err(IdError::TooLong { .. })
78 ));
79 }
80
81 #[test]
82 fn try_new_rejects_nul() {
83 assert_eq!(CollectionId::try_new("ab\0cd"), Err(IdError::ContainsNul));
84 }
85
86 #[test]
87 fn try_new_accepts_max_length() {
88 let exact = "a".repeat(ID_MAX_LEN);
89 assert!(CollectionId::try_new(exact).is_ok());
90 }
91
92 #[test]
93 fn try_new_accepts_unicode() {
94 assert!(CollectionId::try_new("Ünïcödé").is_ok());
96 }
97
98 #[test]
99 fn from_validated_does_not_validate() {
100 let oversized = "z".repeat(ID_MAX_LEN * 2);
103 let c = CollectionId::from_validated(oversized.clone());
104 assert_eq!(c.as_str(), oversized);
105 }
106}