mz_repr/
catalog_item_id.rs1use std::fmt;
11use std::str::FromStr;
12
13use anyhow::{Error, anyhow};
14use mz_lowertest::MzReflect;
15use mz_proto::{RustType, TryFromProtoError};
16#[cfg(any(test, feature = "proptest"))]
17use proptest_derive::Arbitrary;
18use serde::{Deserialize, Serialize};
19
20include!(concat!(env!("OUT_DIR"), "/mz_repr.catalog_item_id.rs"));
21
22#[derive(
24 Clone,
25 Copy,
26 Debug,
27 Eq,
28 PartialEq,
29 Ord,
30 PartialOrd,
31 Hash,
32 Serialize,
33 Deserialize,
34 MzReflect
35)]
36#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
37pub enum CatalogItemId {
38 System(u64),
40 IntrospectionSourceIndex(u64),
42 User(u64),
44 Transient(u64),
46}
47
48impl CatalogItemId {
49 pub fn is_system(&self) -> bool {
51 matches!(
52 self,
53 CatalogItemId::System(_) | CatalogItemId::IntrospectionSourceIndex(_)
54 )
55 }
56
57 pub fn is_user(&self) -> bool {
59 matches!(self, CatalogItemId::User(_))
60 }
61
62 pub fn is_transient(&self) -> bool {
64 matches!(self, CatalogItemId::Transient(_))
65 }
66}
67
68impl FromStr for CatalogItemId {
69 type Err = Error;
70
71 fn from_str(mut s: &str) -> Result<Self, Self::Err> {
72 if s.len() < 2 {
73 return Err(anyhow!("couldn't parse id {}", s));
74 }
75 let tag = s.chars().next().unwrap();
76 s = &s[1..];
77 let variant = match tag {
78 's' => {
79 if Some('i') == s.chars().next() {
80 s = &s[1..];
81 CatalogItemId::IntrospectionSourceIndex
82 } else {
83 CatalogItemId::System
84 }
85 }
86 'u' => CatalogItemId::User,
87 't' => CatalogItemId::Transient,
88 _ => return Err(anyhow!("couldn't parse id {}", s)),
89 };
90 let val: u64 = s.parse()?;
91 Ok(variant(val))
92 }
93}
94
95impl fmt::Display for CatalogItemId {
96 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97 match self {
98 CatalogItemId::System(id) => write!(f, "s{}", id),
99 CatalogItemId::IntrospectionSourceIndex(id) => write!(f, "si{}", id),
100 CatalogItemId::User(id) => write!(f, "u{}", id),
101 CatalogItemId::Transient(id) => write!(f, "t{}", id),
102 }
103 }
104}
105
106impl RustType<ProtoCatalogItemId> for CatalogItemId {
107 fn into_proto(&self) -> ProtoCatalogItemId {
108 use proto_catalog_item_id::Kind::*;
109 ProtoCatalogItemId {
110 kind: Some(match self {
111 CatalogItemId::System(x) => System(*x),
112 CatalogItemId::IntrospectionSourceIndex(x) => IntrospectionSourceIndex(*x),
113 CatalogItemId::User(x) => User(*x),
114 CatalogItemId::Transient(x) => Transient(*x),
115 }),
116 }
117 }
118
119 fn from_proto(proto: ProtoCatalogItemId) -> Result<Self, TryFromProtoError> {
120 use proto_catalog_item_id::Kind::*;
121 match proto.kind {
122 Some(System(x)) => Ok(CatalogItemId::System(x)),
123 Some(IntrospectionSourceIndex(x)) => Ok(CatalogItemId::IntrospectionSourceIndex(x)),
124 Some(User(x)) => Ok(CatalogItemId::User(x)),
125 Some(Transient(x)) => Ok(CatalogItemId::Transient(x)),
126 None => Err(TryFromProtoError::missing_field("ProtoCatalogItemId::kind")),
127 }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use proptest::prelude::*;
134
135 use super::*;
136
137 #[mz_ore::test]
138 fn proptest_catalog_item_id_roundtrips() {
139 fn testcase(og: CatalogItemId) {
140 let s = og.to_string();
141 let rnd: CatalogItemId = s.parse().unwrap();
142 assert_eq!(og, rnd);
143 }
144
145 proptest!(|(id in any::<CatalogItemId>())| {
146 testcase(id);
147 })
148 }
149}