1use std::fmt;
11use std::str::FromStr;
12
13use anyhow::{Error, anyhow};
14use columnar::Columnar;
15use mz_lowertest::MzReflect;
16use mz_ore::id_gen::AtomicIdGen;
17use proptest_derive::Arbitrary;
18use serde::{Deserialize, Serialize};
19
20use crate::CatalogItemId;
21
22#[derive(
28 Arbitrary,
29 Clone,
30 Copy,
31 Debug,
32 Eq,
33 PartialEq,
34 Ord,
35 PartialOrd,
36 Hash,
37 Serialize,
38 Deserialize,
39 MzReflect,
40 Columnar
41)]
42pub enum GlobalId {
43 System(u64),
45 IntrospectionSourceIndex(u64),
47 User(u64),
49 Transient(u64),
51 Explain,
53}
54
55static_assertions::assert_eq_size!(GlobalId, [u8; 16]);
58
59impl GlobalId {
60 pub fn is_system(&self) -> bool {
62 matches!(
63 self,
64 GlobalId::System(_) | GlobalId::IntrospectionSourceIndex(_)
65 )
66 }
67
68 pub fn is_user(&self) -> bool {
70 matches!(self, GlobalId::User(_))
71 }
72
73 pub fn is_transient(&self) -> bool {
75 matches!(self, GlobalId::Transient(_))
76 }
77}
78
79impl FromStr for GlobalId {
80 type Err = Error;
81
82 fn from_str(mut s: &str) -> Result<Self, Self::Err> {
83 if s.len() < 2 {
84 return Err(anyhow!("couldn't parse id {}", s));
85 }
86 if s == "Explained Query" {
87 return Ok(GlobalId::Explain);
88 }
89 let tag = s.chars().next().unwrap();
90 s = &s[1..];
91 let variant = match tag {
92 's' => {
93 if Some('i') == s.chars().next() {
94 s = &s[1..];
95 GlobalId::IntrospectionSourceIndex
96 } else {
97 GlobalId::System
98 }
99 }
100 'u' => GlobalId::User,
101 't' => GlobalId::Transient,
102 _ => return Err(anyhow!("couldn't parse id {}", s)),
103 };
104 let val: u64 = s.parse()?;
105 Ok(variant(val))
106 }
107}
108
109impl fmt::Display for GlobalId {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 match self {
112 GlobalId::System(id) => write!(f, "s{}", id),
113 GlobalId::IntrospectionSourceIndex(id) => write!(f, "si{}", id),
114 GlobalId::User(id) => write!(f, "u{}", id),
115 GlobalId::Transient(id) => write!(f, "t{}", id),
116 GlobalId::Explain => write!(f, "Explained Query"),
117 }
118 }
119}
120
121#[derive(Debug)]
122pub struct TransientIdGen(AtomicIdGen);
123
124impl TransientIdGen {
125 pub fn new() -> Self {
126 let inner = AtomicIdGen::default();
127 let _ = inner.allocate_id();
129 Self(inner)
130 }
131
132 pub fn allocate_id(&self) -> (CatalogItemId, GlobalId) {
133 let inner = self.0.allocate_id();
134 (CatalogItemId::Transient(inner), GlobalId::Transient(inner))
135 }
136}