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