anymap_serde/stable_type_id.rs
1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4/// An opaque holder for a stable, deterministic identifier for a Rust type.
5#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
6#[serde(transparent)]
7pub struct StableTypeId(String);
8
9impl fmt::Display for StableTypeId {
10 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 self.0.fmt(f)
12 }
13}
14
15impl StableTypeId {
16 /// Returns the **stable string key** associated with type `T`.
17 ///
18 /// # Overview
19 ///
20 /// This function produces a deterministic, globally stable identifier for a
21 /// Rust type by returning the fully-qualified name produced by
22 /// [`core::any::type_name`].
23 ///
24 /// The resulting key is:
25 ///
26 /// - **Bijective** – each distinct type maps to a distinct string key.
27 /// - **Deterministic** – the same type always produces the same key within a
28 /// given version of this crate.
29 /// - **Pure** – no side effects; does not depend on runtime state.
30 /// - **Compilation-unit stable** – the returned value does not depend on memory
31 /// layout, type IDs, or other non-portable properties.
32 ///
33 /// This key is used internally by the serializable anymap to index entries by
34 /// their type. Because `TypeId` is not stable across compilation units or
35 /// compiler versions, string keys offer a portable alternative suitable for
36 /// serialization.
37 ///
38 /// # Stability Guarantees
39 ///
40 /// Changing the **implementation of this function is to be considered a breaking change**
41 ///
42 /// Consumers relying on serialized output can therefore depend on this value
43 /// as a long-term stable identifier for the type.
44 ///
45 /// # Caveats
46 ///
47 /// The current implementatino relies on std::any::type_name, which is *NOT* guaranteed to be
48 /// stable across rustc versions, although change is unlikely.
49 ///
50 /// # Examples
51 ///
52 /// ```
53 /// use anymap_serde::StableTypeId;
54 ///
55 /// let k1 = StableTypeId::for_type::<i32>();
56 /// let k2 = StableTypeId::for_type::<Option<String>>();
57 ///
58 /// assert_eq!(format!("{}", k1), "i32");
59 /// assert_eq!(format!("{}", k2), "core::option::Option<alloc::string::String>");
60 /// ```
61 ///
62 /// # Notes
63 ///
64 /// - The function returns an owned `String` rather than a `&'static str`,
65 /// because the underlying representation from `type_name` is returned as a
66 /// borrowed string and needs to be materialized for storage.
67 /// - For generic types, the key includes full type parameters in a canonical
68 /// format.
69 ///
70 /// # See Also
71 ///
72 /// - [`core::any::type_name`] – the underlying mechanism used to generate the key.
73 ///
74 /// # Returns
75 ///
76 /// A stable, deterministic string key uniquely identifying the type `T`.
77 pub fn for_type<T>() -> StableTypeId {
78 StableTypeId(std::any::type_name::<T>().to_string())
79 }
80}