1use std::{
2 any::{Any, TypeId},
3 borrow::Cow,
4 fmt, hash,
5 sync::Arc,
6};
7
8use crate::{
9 Types,
10 datatype::{Generic, Map, NamedDataType, Primitive},
11};
12
13use super::DataType;
14
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub enum Reference {
18 Named(NamedReference),
23 Opaque(OpaqueReference),
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash)]
29#[non_exhaustive]
30pub struct NamedReference {
31 pub(crate) id: NamedId,
32 pub inner: NamedReferenceType,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Hash)]
38pub enum NamedReferenceType {
39 Recursive(RecursiveInlineType),
44 #[non_exhaustive]
47 Inline {
48 dt: Box<DataType>,
50 },
51 #[non_exhaustive]
53 Reference {
54 generics: Vec<(Generic, DataType)>,
56 },
57}
58
59#[derive(Clone, PartialEq, Eq, Hash)]
61#[non_exhaustive]
62pub struct RecursiveInlineType {
63 cycle: Vec<RecursiveInlineFrame>,
64}
65
66#[derive(Clone, PartialEq, Eq, Hash)]
67pub(crate) struct RecursiveInlineFrame {
68 type_name: Cow<'static, str>,
69 generics: Vec<Cow<'static, str>>,
70}
71
72impl RecursiveInlineType {
73 pub(crate) fn from_cycle(cycle: Vec<RecursiveInlineFrame>) -> Self {
74 Self { cycle }
75 }
76
77 fn last_frame(&self) -> Option<&RecursiveInlineFrame> {
78 self.cycle.last()
79 }
80}
81
82impl fmt::Debug for RecursiveInlineType {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 for (idx, ty) in self.cycle.iter().enumerate() {
85 if idx != 0 {
86 f.write_str(" -> ")?;
87 }
88 write!(f, "{ty:?}")?;
89 }
90 Ok(())
91 }
92}
93
94impl RecursiveInlineFrame {
95 pub(crate) fn new(
96 types: &Types,
97 ndt: &NamedDataType,
98 generics: &[(Generic, DataType)],
99 ) -> Self {
100 Self::new_inner(types, named_type_path(ndt), generics)
101 }
102
103 pub(crate) fn from_type_path(
104 types: &Types,
105 type_name: Cow<'static, str>,
106 generics: &[(Generic, DataType)],
107 ) -> Self {
108 Self::new_inner(types, type_name, generics)
109 }
110
111 fn new_inner(
112 types: &Types,
113 type_name: Cow<'static, str>,
114 generics: &[(Generic, DataType)],
115 ) -> Self {
116 Self {
117 type_name,
118 generics: generics
119 .iter()
120 .map(|(_, dt)| render_recursive_inline_generic(types, dt))
121 .collect(),
122 }
123 }
124}
125
126impl fmt::Debug for RecursiveInlineFrame {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 f.write_str(&self.type_name)?;
129 if self.generics.is_empty() {
130 return Ok(());
131 }
132
133 f.write_str("<")?;
134 for (idx, generic) in self.generics.iter().enumerate() {
135 if idx != 0 {
136 f.write_str(", ")?;
137 }
138 f.write_str(generic)?;
139 }
140 f.write_str(">")
141 }
142}
143
144fn named_type_path(ndt: &NamedDataType) -> Cow<'static, str> {
145 if ndt.module_path.is_empty() {
146 ndt.name.clone()
147 } else {
148 Cow::Owned(format!("{}::{}", ndt.module_path, ndt.name))
149 }
150}
151
152fn render_recursive_inline_generic(types: &Types, dt: &DataType) -> Cow<'static, str> {
153 match dt {
154 DataType::Primitive(primitive) => Cow::Borrowed(primitive_type_name(primitive)),
155 DataType::Generic(generic) => generic.name().clone(),
156 DataType::Reference(Reference::Named(reference)) => {
157 render_recursive_inline_named(types, reference)
158 }
159 DataType::Reference(Reference::Opaque(reference)) => Cow::Borrowed(reference.type_name()),
160 DataType::List(list) => {
161 let ty = render_recursive_inline_generic(types, &list.ty);
162 match list.length {
163 Some(length) => Cow::Owned(format!("[{ty}; {length}]")),
164 None => Cow::Owned(format!("Vec<{ty}>")),
165 }
166 }
167 DataType::Map(map) => render_recursive_inline_map(types, map),
168 DataType::Nullable(inner) => Cow::Owned(format!(
169 "Option<{}>",
170 render_recursive_inline_generic(types, inner)
171 )),
172 DataType::Tuple(tuple) => Cow::Owned(format!(
173 "({})",
174 tuple
175 .elements
176 .iter()
177 .map(|dt| render_recursive_inline_generic(types, dt).into_owned())
178 .collect::<Vec<_>>()
179 .join(", ")
180 )),
181 dt => Cow::Owned(format!("{dt:?}")),
182 }
183}
184
185fn render_recursive_inline_named(types: &Types, reference: &NamedReference) -> Cow<'static, str> {
186 if let NamedReferenceType::Recursive(cycle) = &reference.inner
187 && let Some(ty) = cycle.last_frame()
188 {
189 return Cow::Owned(format!("{ty:?}"));
190 }
191
192 let Some(ndt) = types.get(reference) else {
193 return Cow::Owned(format!("{reference:?}"));
194 };
195
196 let mut out = named_type_path(ndt).into_owned();
197 if let NamedReferenceType::Reference { generics } = &reference.inner
198 && !generics.is_empty()
199 {
200 out.push('<');
201 out.push_str(
202 &generics
203 .iter()
204 .map(|(_, dt)| render_recursive_inline_generic(types, dt).into_owned())
205 .collect::<Vec<_>>()
206 .join(", "),
207 );
208 out.push('>');
209 }
210 Cow::Owned(out)
211}
212
213fn render_recursive_inline_map(types: &Types, map: &Map) -> Cow<'static, str> {
214 Cow::Owned(format!(
215 "HashMap<{}, {}>",
216 render_recursive_inline_generic(types, map.key_ty()),
217 render_recursive_inline_generic(types, map.value_ty())
218 ))
219}
220
221fn primitive_type_name(primitive: &Primitive) -> &'static str {
222 match primitive {
223 Primitive::i8 => "i8",
224 Primitive::i16 => "i16",
225 Primitive::i32 => "i32",
226 Primitive::i64 => "i64",
227 Primitive::i128 => "i128",
228 Primitive::u8 => "u8",
229 Primitive::u16 => "u16",
230 Primitive::u32 => "u32",
231 Primitive::u64 => "u64",
232 Primitive::u128 => "u128",
233 Primitive::isize => "isize",
234 Primitive::usize => "usize",
235 Primitive::f16 => "f16",
236 Primitive::f32 => "f32",
237 Primitive::f64 => "f64",
238 Primitive::f128 => "f128",
239 Primitive::bool => "bool",
240 Primitive::str => "String",
241 Primitive::char => "char",
242 }
243}
244
245#[derive(Clone)]
260pub struct OpaqueReference(Arc<dyn DynOpaqueReference>);
261
262trait DynOpaqueReference: Any + Send + Sync {
263 fn type_name(&self) -> &'static str;
264 fn hash(&self, hasher: &mut dyn hash::Hasher);
265 fn eq(&self, other: &dyn Any) -> bool;
266 fn as_any(&self) -> &dyn Any;
267}
268
269#[derive(Debug)]
270struct OpaqueReferenceInner<T>(T);
271impl<T: hash::Hash + Eq + Send + Sync + 'static> DynOpaqueReference for OpaqueReferenceInner<T> {
272 fn type_name(&self) -> &'static str {
273 std::any::type_name::<T>()
274 }
275 fn hash(&self, mut hasher: &mut dyn hash::Hasher) {
276 self.0.hash(&mut hasher)
277 }
278 fn eq(&self, other: &dyn Any) -> bool {
279 other
280 .downcast_ref::<T>()
281 .map(|other| self.0 == *other)
282 .unwrap_or_default()
283 }
284 fn as_any(&self) -> &dyn Any {
285 &self.0
286 }
287}
288
289impl fmt::Debug for OpaqueReference {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 f.debug_tuple("OpaqueReference")
292 .field(&self.0.type_name())
293 .finish()
294 }
295}
296
297impl PartialEq for OpaqueReference {
298 fn eq(&self, other: &Self) -> bool {
299 self.0.eq(other.0.as_any())
300 }
301}
302
303impl Eq for OpaqueReference {}
304
305impl hash::Hash for OpaqueReference {
306 fn hash<H: hash::Hasher>(&self, state: &mut H) {
307 self.0.hash(state)
308 }
309}
310
311impl OpaqueReference {
312 pub fn type_name(&self) -> &'static str {
314 self.0.type_name()
315 }
316
317 pub fn type_id(&self) -> TypeId {
319 self.0.as_any().type_id()
320 }
321
322 pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
324 self.0.as_any().downcast_ref::<T>()
325 }
326}
327
328impl Reference {
329 pub fn opaque<T: hash::Hash + Eq + Send + Sync + 'static>(state: T) -> Self {
338 Self::Opaque(OpaqueReference(Arc::new(OpaqueReferenceInner(state))))
339 }
340
341 pub fn ty_eq(&self, other: &Reference) -> bool {
346 match (self, other) {
347 (Reference::Named(a), Reference::Named(b)) => a.id == b.id,
348 (Reference::Opaque(a), Reference::Opaque(b)) => *a == *b,
349 _ => false,
350 }
351 }
352}
353
354impl From<Reference> for DataType {
355 fn from(r: Reference) -> Self {
356 Self::Reference(r)
357 }
358}
359
360#[derive(Clone)]
365pub(crate) enum NamedId {
366 Static(&'static str),
368 Dynamic(Arc<()>),
369}
370
371impl PartialEq for NamedId {
372 fn eq(&self, other: &Self) -> bool {
373 match (self, other) {
374 (NamedId::Static(a), NamedId::Static(b)) => a == b,
375 (NamedId::Dynamic(a), NamedId::Dynamic(b)) => Arc::ptr_eq(a, b),
376 _ => false,
377 }
378 }
379}
380impl Eq for NamedId {}
381
382impl hash::Hash for NamedId {
383 fn hash<H: hash::Hasher>(&self, state: &mut H) {
384 match self {
385 NamedId::Static(s) => s.hash(state),
386 NamedId::Dynamic(p) => std::ptr::hash(Arc::as_ptr(p), state),
387 }
388 }
389}
390
391impl fmt::Debug for NamedId {
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 match self {
394 NamedId::Static(s) => write!(f, "s:{}", s),
395 NamedId::Dynamic(p) => write!(f, "d{:p}", Arc::as_ptr(p)),
396 }
397 }
398}