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