Skip to main content

miniextendr_api/
externalptr_std.rs

1//! `TypedExternal` implementations for standard library types.
2//!
3//! This module provides `TypedExternal` implementations for common std types,
4//! allowing them to be stored in `ExternalPtr<T>` without manual implementation.
5//!
6//! # Generic Types
7//!
8//! For generic types like `Vec<T>`, the type name does not include the type parameter
9//! (e.g., `Vec<i32>` and `Vec<String>` both have type name "Vec"). This means type
10//! checking at the R level won't distinguish between different instantiations.
11//! If you need stricter type safety, create a newtype wrapper and derive `ExternalPtr`.
12
13use crate::externalptr::TypedExternal;
14
15/// Implement TypedExternal for a concrete type.
16/// For standard library types, we use the simple name for both display and ID.
17macro_rules! impl_te {
18    ($ty:ty, $name:literal) => {
19        impl TypedExternal for $ty {
20            const TYPE_NAME: &'static str = $name;
21            const TYPE_NAME_CSTR: &'static [u8] = concat!($name, "\0").as_bytes();
22            const TYPE_ID_CSTR: &'static [u8] = concat!("std::", $name, "\0").as_bytes();
23        }
24    };
25}
26
27/// Implement TypedExternal for a generic type with 'static bounds.
28/// For standard library types, we prefix the ID with "std::" for clarity.
29macro_rules! impl_te_generic {
30    (<$g:ident: ?Sized> $ty:ty, $name:literal) => {
31        impl<$g: ?Sized + 'static> TypedExternal for $ty {
32            const TYPE_NAME: &'static str = $name;
33            const TYPE_NAME_CSTR: &'static [u8] = concat!($name, "\0").as_bytes();
34            const TYPE_ID_CSTR: &'static [u8] = concat!("std::", $name, "\0").as_bytes();
35        }
36    };
37    (<$($g:ident),+> $ty:ty, $name:literal) => {
38        impl<$($g: 'static),+> TypedExternal for $ty {
39            const TYPE_NAME: &'static str = $name;
40            const TYPE_NAME_CSTR: &'static [u8] = concat!($name, "\0").as_bytes();
41            const TYPE_ID_CSTR: &'static [u8] = concat!("std::", $name, "\0").as_bytes();
42        }
43    };
44    (<$($g:ident : $bound:path),+> $ty:ty, $name:literal) => {
45        impl<$($g: $bound + 'static),+> TypedExternal for $ty {
46            const TYPE_NAME: &'static str = $name;
47            const TYPE_NAME_CSTR: &'static [u8] = concat!($name, "\0").as_bytes();
48            const TYPE_ID_CSTR: &'static [u8] = concat!("std::", $name, "\0").as_bytes();
49        }
50    };
51}
52
53// region: Primitives
54
55impl TypedExternal for bool {
    const TYPE_NAME: &'static str = "bool";
    const TYPE_NAME_CSTR: &'static [u8] = "bool\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::bool\u{0}".as_bytes();
}impl_te!(bool, "bool");
56impl TypedExternal for char {
    const TYPE_NAME: &'static str = "char";
    const TYPE_NAME_CSTR: &'static [u8] = "char\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::char\u{0}".as_bytes();
}impl_te!(char, "char");
57impl TypedExternal for i8 {
    const TYPE_NAME: &'static str = "i8";
    const TYPE_NAME_CSTR: &'static [u8] = "i8\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::i8\u{0}".as_bytes();
}impl_te!(i8, "i8");
58impl TypedExternal for i16 {
    const TYPE_NAME: &'static str = "i16";
    const TYPE_NAME_CSTR: &'static [u8] = "i16\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::i16\u{0}".as_bytes();
}impl_te!(i16, "i16");
59impl TypedExternal for i32 {
    const TYPE_NAME: &'static str = "i32";
    const TYPE_NAME_CSTR: &'static [u8] = "i32\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::i32\u{0}".as_bytes();
}impl_te!(i32, "i32");
60impl TypedExternal for i64 {
    const TYPE_NAME: &'static str = "i64";
    const TYPE_NAME_CSTR: &'static [u8] = "i64\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::i64\u{0}".as_bytes();
}impl_te!(i64, "i64");
61impl TypedExternal for i128 {
    const TYPE_NAME: &'static str = "i128";
    const TYPE_NAME_CSTR: &'static [u8] = "i128\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::i128\u{0}".as_bytes();
}impl_te!(i128, "i128");
62impl TypedExternal for isize {
    const TYPE_NAME: &'static str = "isize";
    const TYPE_NAME_CSTR: &'static [u8] = "isize\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::isize\u{0}".as_bytes();
}impl_te!(isize, "isize");
63impl TypedExternal for u8 {
    const TYPE_NAME: &'static str = "u8";
    const TYPE_NAME_CSTR: &'static [u8] = "u8\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::u8\u{0}".as_bytes();
}impl_te!(u8, "u8");
64impl TypedExternal for u16 {
    const TYPE_NAME: &'static str = "u16";
    const TYPE_NAME_CSTR: &'static [u8] = "u16\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::u16\u{0}".as_bytes();
}impl_te!(u16, "u16");
65impl TypedExternal for u32 {
    const TYPE_NAME: &'static str = "u32";
    const TYPE_NAME_CSTR: &'static [u8] = "u32\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::u32\u{0}".as_bytes();
}impl_te!(u32, "u32");
66impl TypedExternal for u64 {
    const TYPE_NAME: &'static str = "u64";
    const TYPE_NAME_CSTR: &'static [u8] = "u64\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::u64\u{0}".as_bytes();
}impl_te!(u64, "u64");
67impl TypedExternal for u128 {
    const TYPE_NAME: &'static str = "u128";
    const TYPE_NAME_CSTR: &'static [u8] = "u128\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::u128\u{0}".as_bytes();
}impl_te!(u128, "u128");
68impl TypedExternal for usize {
    const TYPE_NAME: &'static str = "usize";
    const TYPE_NAME_CSTR: &'static [u8] = "usize\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::usize\u{0}".as_bytes();
}impl_te!(usize, "usize");
69impl TypedExternal for f32 {
    const TYPE_NAME: &'static str = "f32";
    const TYPE_NAME_CSTR: &'static [u8] = "f32\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::f32\u{0}".as_bytes();
}impl_te!(f32, "f32");
70impl TypedExternal for f64 {
    const TYPE_NAME: &'static str = "f64";
    const TYPE_NAME_CSTR: &'static [u8] = "f64\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::f64\u{0}".as_bytes();
}impl_te!(f64, "f64");
71// endregion
72
73// region: Strings
74
75impl TypedExternal for String {
    const TYPE_NAME: &'static str = "String";
    const TYPE_NAME_CSTR: &'static [u8] = "String\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::String\u{0}".as_bytes();
}impl_te!(String, "String");
76impl TypedExternal for std::ffi::CString {
    const TYPE_NAME: &'static str = "CString";
    const TYPE_NAME_CSTR: &'static [u8] = "CString\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::CString\u{0}".as_bytes();
}impl_te!(std::ffi::CString, "CString");
77impl TypedExternal for std::ffi::OsString {
    const TYPE_NAME: &'static str = "OsString";
    const TYPE_NAME_CSTR: &'static [u8] = "OsString\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::OsString\u{0}".as_bytes();
}impl_te!(std::ffi::OsString, "OsString");
78impl TypedExternal for std::path::PathBuf {
    const TYPE_NAME: &'static str = "PathBuf";
    const TYPE_NAME_CSTR: &'static [u8] = "PathBuf\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::PathBuf\u{0}".as_bytes();
}impl_te!(std::path::PathBuf, "PathBuf");
79// endregion
80
81// region: Collections
82
83impl<T: 'static> TypedExternal for Vec<T> {
    const TYPE_NAME: &'static str = "Vec";
    const TYPE_NAME_CSTR: &'static [u8] = "Vec\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Vec\u{0}".as_bytes();
}impl_te_generic!(<T> Vec<T>, "Vec");
84impl<T: 'static> TypedExternal for std::collections::VecDeque<T> {
    const TYPE_NAME: &'static str = "VecDeque";
    const TYPE_NAME_CSTR: &'static [u8] = "VecDeque\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::VecDeque\u{0}".as_bytes();
}impl_te_generic!(<T> std::collections::VecDeque<T>, "VecDeque");
85impl<T: 'static> TypedExternal for std::collections::LinkedList<T> {
    const TYPE_NAME: &'static str = "LinkedList";
    const TYPE_NAME_CSTR: &'static [u8] = "LinkedList\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::LinkedList\u{0}".as_bytes();
}impl_te_generic!(<T> std::collections::LinkedList<T>, "LinkedList");
86impl<T: 'static> TypedExternal for std::collections::BinaryHeap<T> {
    const TYPE_NAME: &'static str = "BinaryHeap";
    const TYPE_NAME_CSTR: &'static [u8] = "BinaryHeap\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::BinaryHeap\u{0}".as_bytes();
}impl_te_generic!(<T> std::collections::BinaryHeap<T>, "BinaryHeap");
87impl<K: 'static, V: 'static> TypedExternal for std::collections::HashMap<K, V>
    {
    const TYPE_NAME: &'static str = "HashMap";
    const TYPE_NAME_CSTR: &'static [u8] = "HashMap\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::HashMap\u{0}".as_bytes();
}impl_te_generic!(<K, V> std::collections::HashMap<K, V>, "HashMap");
88impl<K: 'static, V: 'static> TypedExternal for
    std::collections::BTreeMap<K, V> {
    const TYPE_NAME: &'static str = "BTreeMap";
    const TYPE_NAME_CSTR: &'static [u8] = "BTreeMap\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::BTreeMap\u{0}".as_bytes();
}impl_te_generic!(<K, V> std::collections::BTreeMap<K, V>, "BTreeMap");
89impl<T: 'static> TypedExternal for std::collections::HashSet<T> {
    const TYPE_NAME: &'static str = "HashSet";
    const TYPE_NAME_CSTR: &'static [u8] = "HashSet\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::HashSet\u{0}".as_bytes();
}impl_te_generic!(<T> std::collections::HashSet<T>, "HashSet");
90impl<T: 'static> TypedExternal for std::collections::BTreeSet<T> {
    const TYPE_NAME: &'static str = "BTreeSet";
    const TYPE_NAME_CSTR: &'static [u8] = "BTreeSet\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::BTreeSet\u{0}".as_bytes();
}impl_te_generic!(<T> std::collections::BTreeSet<T>, "BTreeSet");
91// endregion
92
93// region: Smart Pointers
94
95impl<T: 'static> TypedExternal for Box<T> {
    const TYPE_NAME: &'static str = "Box";
    const TYPE_NAME_CSTR: &'static [u8] = "Box\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Box\u{0}".as_bytes();
}impl_te_generic!(<T> Box<T>, "Box");
96
97// Box<[T]> is a special case - it's a fat pointer (Sized) wrapping a DST.
98// Unlike Box<T> where T: Sized, Box<[T]> can store dynamically-sized slices.
99// This is useful for ALTREP when you want fixed-size heap allocation without
100// Vec's capacity overhead.
101impl<T: 'static> TypedExternal for Box<[T]> {
102    const TYPE_NAME: &'static str = "BoxSlice";
103    const TYPE_NAME_CSTR: &'static [u8] = b"BoxSlice\0";
104    const TYPE_ID_CSTR: &'static [u8] = b"std::BoxSlice\0";
105}
106
107// Cow<'a, [T]> is a fat pointer like Box<[T]> — needs explicit impl.
108impl<T: Clone + 'static> TypedExternal for std::borrow::Cow<'static, [T]> {
109    const TYPE_NAME: &'static str = "CowSlice";
110    const TYPE_NAME_CSTR: &'static [u8] = b"CowSlice\0";
111    const TYPE_ID_CSTR: &'static [u8] = b"std::CowSlice\0";
112}
113
114impl<T: ?Sized + 'static> TypedExternal for std::rc::Rc<T> {
    const TYPE_NAME: &'static str = "Rc";
    const TYPE_NAME_CSTR: &'static [u8] = "Rc\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Rc\u{0}".as_bytes();
}impl_te_generic!(<T: ?Sized> std::rc::Rc<T>, "Rc");
115impl<T: ?Sized + 'static> TypedExternal for std::sync::Arc<T> {
    const TYPE_NAME: &'static str = "Arc";
    const TYPE_NAME_CSTR: &'static [u8] = "Arc\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Arc\u{0}".as_bytes();
}impl_te_generic!(<T: ?Sized> std::sync::Arc<T>, "Arc");
116impl<T: 'static> TypedExternal for std::cell::Cell<T> {
    const TYPE_NAME: &'static str = "Cell";
    const TYPE_NAME_CSTR: &'static [u8] = "Cell\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Cell\u{0}".as_bytes();
}impl_te_generic!(<T> std::cell::Cell<T>, "Cell");
117impl<T: 'static> TypedExternal for std::cell::RefCell<T> {
    const TYPE_NAME: &'static str = "RefCell";
    const TYPE_NAME_CSTR: &'static [u8] = "RefCell\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::RefCell\u{0}".as_bytes();
}impl_te_generic!(<T> std::cell::RefCell<T>, "RefCell");
118impl<T: 'static> TypedExternal for std::cell::UnsafeCell<T> {
    const TYPE_NAME: &'static str = "UnsafeCell";
    const TYPE_NAME_CSTR: &'static [u8] = "UnsafeCell\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::UnsafeCell\u{0}".as_bytes();
}impl_te_generic!(<T> std::cell::UnsafeCell<T>, "UnsafeCell");
119impl<T: 'static> TypedExternal for std::sync::Mutex<T> {
    const TYPE_NAME: &'static str = "Mutex";
    const TYPE_NAME_CSTR: &'static [u8] = "Mutex\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Mutex\u{0}".as_bytes();
}impl_te_generic!(<T> std::sync::Mutex<T>, "Mutex");
120impl<T: 'static> TypedExternal for std::sync::RwLock<T> {
    const TYPE_NAME: &'static str = "RwLock";
    const TYPE_NAME_CSTR: &'static [u8] = "RwLock\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::RwLock\u{0}".as_bytes();
}impl_te_generic!(<T> std::sync::RwLock<T>, "RwLock");
121impl<T: 'static> TypedExternal for std::sync::OnceLock<T> {
    const TYPE_NAME: &'static str = "OnceLock";
    const TYPE_NAME_CSTR: &'static [u8] = "OnceLock\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::OnceLock\u{0}".as_bytes();
}impl_te_generic!(<T> std::sync::OnceLock<T>, "OnceLock");
122impl<T: 'static> TypedExternal for std::pin::Pin<T> {
    const TYPE_NAME: &'static str = "Pin";
    const TYPE_NAME_CSTR: &'static [u8] = "Pin\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Pin\u{0}".as_bytes();
}impl_te_generic!(<T> std::pin::Pin<T>, "Pin");
123// ManuallyDrop<T> shares T's R-facing display/diagnostic symbols. Concrete
124// access still goes through Any::downcast, where ManuallyDrop<T> and T remain
125// distinct TypeIds despite their identical layouts.
126impl<T: TypedExternal> TypedExternal for std::mem::ManuallyDrop<T> {
127    const TYPE_NAME: &'static str = T::TYPE_NAME;
128    const TYPE_NAME_CSTR: &'static [u8] = T::TYPE_NAME_CSTR;
129    const TYPE_ID_CSTR: &'static [u8] = T::TYPE_ID_CSTR;
130}
131impl<T: 'static> TypedExternal for std::mem::MaybeUninit<T> {
    const TYPE_NAME: &'static str = "MaybeUninit";
    const TYPE_NAME_CSTR: &'static [u8] = "MaybeUninit\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::MaybeUninit\u{0}".as_bytes();
}impl_te_generic!(<T> std::mem::MaybeUninit<T>, "MaybeUninit");
132impl<T: 'static> TypedExternal for std::marker::PhantomData<T> {
    const TYPE_NAME: &'static str = "PhantomData";
    const TYPE_NAME_CSTR: &'static [u8] = "PhantomData\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::PhantomData\u{0}".as_bytes();
}impl_te_generic!(<T> std::marker::PhantomData<T>, "PhantomData");
133// endregion
134
135// region: Option / Result
136
137impl<T: 'static> TypedExternal for Option<T> {
    const TYPE_NAME: &'static str = "Option";
    const TYPE_NAME_CSTR: &'static [u8] = "Option\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Option\u{0}".as_bytes();
}impl_te_generic!(<T> Option<T>, "Option");
138impl<T: 'static, E: 'static> TypedExternal for Result<T, E> {
    const TYPE_NAME: &'static str = "Result";
    const TYPE_NAME_CSTR: &'static [u8] = "Result\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Result\u{0}".as_bytes();
}impl_te_generic!(<T, E> Result<T, E>, "Result");
139// endregion
140
141// region: Ranges
142
143impl<T: 'static> TypedExternal for std::ops::Range<T> {
    const TYPE_NAME: &'static str = "Range";
    const TYPE_NAME_CSTR: &'static [u8] = "Range\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Range\u{0}".as_bytes();
}impl_te_generic!(<T> std::ops::Range<T>, "Range");
144impl<T: 'static> TypedExternal for std::ops::RangeInclusive<T> {
    const TYPE_NAME: &'static str = "RangeInclusive";
    const TYPE_NAME_CSTR: &'static [u8] = "RangeInclusive\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::RangeInclusive\u{0}".as_bytes();
}impl_te_generic!(<T> std::ops::RangeInclusive<T>, "RangeInclusive");
145impl<T: 'static> TypedExternal for std::ops::RangeFrom<T> {
    const TYPE_NAME: &'static str = "RangeFrom";
    const TYPE_NAME_CSTR: &'static [u8] = "RangeFrom\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::RangeFrom\u{0}".as_bytes();
}impl_te_generic!(<T> std::ops::RangeFrom<T>, "RangeFrom");
146impl<T: 'static> TypedExternal for std::ops::RangeTo<T> {
    const TYPE_NAME: &'static str = "RangeTo";
    const TYPE_NAME_CSTR: &'static [u8] = "RangeTo\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::RangeTo\u{0}".as_bytes();
}impl_te_generic!(<T> std::ops::RangeTo<T>, "RangeTo");
147impl<T: 'static> TypedExternal for std::ops::RangeToInclusive<T> {
    const TYPE_NAME: &'static str = "RangeToInclusive";
    const TYPE_NAME_CSTR: &'static [u8] = "RangeToInclusive\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] =
        "std::RangeToInclusive\u{0}".as_bytes();
}impl_te_generic!(<T> std::ops::RangeToInclusive<T>, "RangeToInclusive");
148impl TypedExternal for std::ops::RangeFull {
    const TYPE_NAME: &'static str = "RangeFull";
    const TYPE_NAME_CSTR: &'static [u8] = "RangeFull\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::RangeFull\u{0}".as_bytes();
}impl_te!(std::ops::RangeFull, "RangeFull");
149// endregion
150
151// region: I/O
152
153impl TypedExternal for std::fs::File {
    const TYPE_NAME: &'static str = "File";
    const TYPE_NAME_CSTR: &'static [u8] = "File\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::File\u{0}".as_bytes();
}impl_te!(std::fs::File, "File");
154impl<R: std::io::Read + 'static> TypedExternal for std::io::BufReader<R> {
    const TYPE_NAME: &'static str = "BufReader";
    const TYPE_NAME_CSTR: &'static [u8] = "BufReader\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::BufReader\u{0}".as_bytes();
}impl_te_generic!(<R: std::io::Read> std::io::BufReader<R>, "BufReader");
155impl<W: std::io::Write + 'static> TypedExternal for std::io::BufWriter<W> {
    const TYPE_NAME: &'static str = "BufWriter";
    const TYPE_NAME_CSTR: &'static [u8] = "BufWriter\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::BufWriter\u{0}".as_bytes();
}impl_te_generic!(<W: std::io::Write> std::io::BufWriter<W>, "BufWriter");
156impl<T: 'static> TypedExternal for std::io::Cursor<T> {
    const TYPE_NAME: &'static str = "Cursor";
    const TYPE_NAME_CSTR: &'static [u8] = "Cursor\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Cursor\u{0}".as_bytes();
}impl_te_generic!(<T> std::io::Cursor<T>, "Cursor");
157// endregion
158
159// region: Time
160
161impl TypedExternal for std::time::Duration {
    const TYPE_NAME: &'static str = "Duration";
    const TYPE_NAME_CSTR: &'static [u8] = "Duration\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Duration\u{0}".as_bytes();
}impl_te!(std::time::Duration, "Duration");
162impl TypedExternal for std::time::Instant {
    const TYPE_NAME: &'static str = "Instant";
    const TYPE_NAME_CSTR: &'static [u8] = "Instant\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Instant\u{0}".as_bytes();
}impl_te!(std::time::Instant, "Instant");
163impl TypedExternal for std::time::SystemTime {
    const TYPE_NAME: &'static str = "SystemTime";
    const TYPE_NAME_CSTR: &'static [u8] = "SystemTime\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::SystemTime\u{0}".as_bytes();
}impl_te!(std::time::SystemTime, "SystemTime");
164// endregion
165
166// region: Networking
167
168impl TypedExternal for std::net::TcpStream {
    const TYPE_NAME: &'static str = "TcpStream";
    const TYPE_NAME_CSTR: &'static [u8] = "TcpStream\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::TcpStream\u{0}".as_bytes();
}impl_te!(std::net::TcpStream, "TcpStream");
169impl TypedExternal for std::net::TcpListener {
    const TYPE_NAME: &'static str = "TcpListener";
    const TYPE_NAME_CSTR: &'static [u8] = "TcpListener\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::TcpListener\u{0}".as_bytes();
}impl_te!(std::net::TcpListener, "TcpListener");
170impl TypedExternal for std::net::UdpSocket {
    const TYPE_NAME: &'static str = "UdpSocket";
    const TYPE_NAME_CSTR: &'static [u8] = "UdpSocket\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::UdpSocket\u{0}".as_bytes();
}impl_te!(std::net::UdpSocket, "UdpSocket");
171impl TypedExternal for std::net::IpAddr {
    const TYPE_NAME: &'static str = "IpAddr";
    const TYPE_NAME_CSTR: &'static [u8] = "IpAddr\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::IpAddr\u{0}".as_bytes();
}impl_te!(std::net::IpAddr, "IpAddr");
172impl TypedExternal for std::net::Ipv4Addr {
    const TYPE_NAME: &'static str = "Ipv4Addr";
    const TYPE_NAME_CSTR: &'static [u8] = "Ipv4Addr\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Ipv4Addr\u{0}".as_bytes();
}impl_te!(std::net::Ipv4Addr, "Ipv4Addr");
173impl TypedExternal for std::net::Ipv6Addr {
    const TYPE_NAME: &'static str = "Ipv6Addr";
    const TYPE_NAME_CSTR: &'static [u8] = "Ipv6Addr\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Ipv6Addr\u{0}".as_bytes();
}impl_te!(std::net::Ipv6Addr, "Ipv6Addr");
174impl TypedExternal for std::net::SocketAddr {
    const TYPE_NAME: &'static str = "SocketAddr";
    const TYPE_NAME_CSTR: &'static [u8] = "SocketAddr\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::SocketAddr\u{0}".as_bytes();
}impl_te!(std::net::SocketAddr, "SocketAddr");
175impl TypedExternal for std::net::SocketAddrV4 {
    const TYPE_NAME: &'static str = "SocketAddrV4";
    const TYPE_NAME_CSTR: &'static [u8] = "SocketAddrV4\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::SocketAddrV4\u{0}".as_bytes();
}impl_te!(std::net::SocketAddrV4, "SocketAddrV4");
176impl TypedExternal for std::net::SocketAddrV6 {
    const TYPE_NAME: &'static str = "SocketAddrV6";
    const TYPE_NAME_CSTR: &'static [u8] = "SocketAddrV6\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::SocketAddrV6\u{0}".as_bytes();
}impl_te!(std::net::SocketAddrV6, "SocketAddrV6");
177// endregion
178
179// region: Threading
180
181impl TypedExternal for std::thread::Thread {
    const TYPE_NAME: &'static str = "Thread";
    const TYPE_NAME_CSTR: &'static [u8] = "Thread\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Thread\u{0}".as_bytes();
}impl_te!(std::thread::Thread, "Thread");
182impl<T: 'static> TypedExternal for std::thread::JoinHandle<T> {
    const TYPE_NAME: &'static str = "JoinHandle";
    const TYPE_NAME_CSTR: &'static [u8] = "JoinHandle\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::JoinHandle\u{0}".as_bytes();
}impl_te_generic!(<T> std::thread::JoinHandle<T>, "JoinHandle");
183impl<T: 'static> TypedExternal for std::sync::mpsc::Sender<T> {
    const TYPE_NAME: &'static str = "Sender";
    const TYPE_NAME_CSTR: &'static [u8] = "Sender\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Sender\u{0}".as_bytes();
}impl_te_generic!(<T> std::sync::mpsc::Sender<T>, "Sender");
184impl<T: 'static> TypedExternal for std::sync::mpsc::SyncSender<T> {
    const TYPE_NAME: &'static str = "SyncSender";
    const TYPE_NAME_CSTR: &'static [u8] = "SyncSender\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::SyncSender\u{0}".as_bytes();
}impl_te_generic!(<T> std::sync::mpsc::SyncSender<T>, "SyncSender");
185impl<T: 'static> TypedExternal for std::sync::mpsc::Receiver<T> {
    const TYPE_NAME: &'static str = "Receiver";
    const TYPE_NAME_CSTR: &'static [u8] = "Receiver\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Receiver\u{0}".as_bytes();
}impl_te_generic!(<T> std::sync::mpsc::Receiver<T>, "Receiver");
186impl TypedExternal for std::sync::Barrier {
    const TYPE_NAME: &'static str = "Barrier";
    const TYPE_NAME_CSTR: &'static [u8] = "Barrier\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Barrier\u{0}".as_bytes();
}impl_te!(std::sync::Barrier, "Barrier");
187impl TypedExternal for std::sync::BarrierWaitResult {
    const TYPE_NAME: &'static str = "BarrierWaitResult";
    const TYPE_NAME_CSTR: &'static [u8] = "BarrierWaitResult\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] =
        "std::BarrierWaitResult\u{0}".as_bytes();
}impl_te!(std::sync::BarrierWaitResult, "BarrierWaitResult");
188// endregion
189
190// region: Atomics
191
192impl TypedExternal for std::sync::atomic::AtomicBool {
    const TYPE_NAME: &'static str = "AtomicBool";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicBool\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicBool\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicBool, "AtomicBool");
193impl TypedExternal for std::sync::atomic::AtomicI8 {
    const TYPE_NAME: &'static str = "AtomicI8";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicI8\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicI8\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicI8, "AtomicI8");
194impl TypedExternal for std::sync::atomic::AtomicI16 {
    const TYPE_NAME: &'static str = "AtomicI16";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicI16\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicI16\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicI16, "AtomicI16");
195impl TypedExternal for std::sync::atomic::AtomicI32 {
    const TYPE_NAME: &'static str = "AtomicI32";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicI32\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicI32\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicI32, "AtomicI32");
196impl TypedExternal for std::sync::atomic::AtomicI64 {
    const TYPE_NAME: &'static str = "AtomicI64";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicI64\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicI64\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicI64, "AtomicI64");
197impl TypedExternal for std::sync::atomic::AtomicIsize {
    const TYPE_NAME: &'static str = "AtomicIsize";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicIsize\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicIsize\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicIsize, "AtomicIsize");
198impl TypedExternal for std::sync::atomic::AtomicU8 {
    const TYPE_NAME: &'static str = "AtomicU8";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicU8\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicU8\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicU8, "AtomicU8");
199impl TypedExternal for std::sync::atomic::AtomicU16 {
    const TYPE_NAME: &'static str = "AtomicU16";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicU16\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicU16\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicU16, "AtomicU16");
200impl TypedExternal for std::sync::atomic::AtomicU32 {
    const TYPE_NAME: &'static str = "AtomicU32";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicU32\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicU32\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicU32, "AtomicU32");
201impl TypedExternal for std::sync::atomic::AtomicU64 {
    const TYPE_NAME: &'static str = "AtomicU64";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicU64\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicU64\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicU64, "AtomicU64");
202impl TypedExternal for std::sync::atomic::AtomicUsize {
    const TYPE_NAME: &'static str = "AtomicUsize";
    const TYPE_NAME_CSTR: &'static [u8] = "AtomicUsize\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::AtomicUsize\u{0}".as_bytes();
}impl_te!(std::sync::atomic::AtomicUsize, "AtomicUsize");
203// endregion
204
205// region: Numeric wrappers
206
207// Note: NonZero<T> requires T: ZeroablePrimitive (sealed trait), so we use aliases
208impl TypedExternal for std::num::NonZeroI8 {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroI8, "NonZero");
209impl TypedExternal for std::num::NonZeroI16 {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroI16, "NonZero");
210impl TypedExternal for std::num::NonZeroI32 {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroI32, "NonZero");
211impl TypedExternal for std::num::NonZeroI64 {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroI64, "NonZero");
212impl TypedExternal for std::num::NonZeroI128 {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroI128, "NonZero");
213impl TypedExternal for std::num::NonZeroIsize {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroIsize, "NonZero");
214impl TypedExternal for std::num::NonZeroU8 {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroU8, "NonZero");
215impl TypedExternal for std::num::NonZeroU16 {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroU16, "NonZero");
216impl TypedExternal for std::num::NonZeroU32 {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroU32, "NonZero");
217impl TypedExternal for std::num::NonZeroU64 {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroU64, "NonZero");
218impl TypedExternal for std::num::NonZeroU128 {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroU128, "NonZero");
219impl TypedExternal for std::num::NonZeroUsize {
    const TYPE_NAME: &'static str = "NonZero";
    const TYPE_NAME_CSTR: &'static [u8] = "NonZero\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::NonZero\u{0}".as_bytes();
}impl_te!(std::num::NonZeroUsize, "NonZero");
220impl<T: 'static> TypedExternal for std::num::Wrapping<T> {
    const TYPE_NAME: &'static str = "Wrapping";
    const TYPE_NAME_CSTR: &'static [u8] = "Wrapping\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Wrapping\u{0}".as_bytes();
}impl_te_generic!(<T> std::num::Wrapping<T>, "Wrapping");
221impl<T: 'static> TypedExternal for std::num::Saturating<T> {
    const TYPE_NAME: &'static str = "Saturating";
    const TYPE_NAME_CSTR: &'static [u8] = "Saturating\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Saturating\u{0}".as_bytes();
}impl_te_generic!(<T> std::num::Saturating<T>, "Saturating");
222// endregion
223
224// region: Tuples (1-12 elements)
225
226macro_rules! impl_tuple_typed_external {
227    ($n:literal, $name:literal; $($T:ident $R:ident $idx:tt),+) => {
228        impl_te_generic!(<$($T),+> ($($T,)+), $name);
229    };
230}
231
232impl<A: 'static, B: 'static, C: 'static, D: 'static, E: 'static, F: 'static,
    G: 'static, H: 'static, I: 'static, J: 'static, K: 'static, L: 'static>
    TypedExternal for (A, B, C, D, E, F, G, H, I, J, K, L) {
    const TYPE_NAME: &'static str = "Tuple12";
    const TYPE_NAME_CSTR: &'static [u8] = "Tuple12\u{0}".as_bytes();
    const TYPE_ID_CSTR: &'static [u8] = "std::Tuple12\u{0}".as_bytes();
}crate::tuple_macros::for_each_tuple!(impl_tuple_typed_external);
233// endregion
234
235// region: Arrays (const generic)
236
237impl<T: 'static, const N: usize> TypedExternal for [T; N] {
238    const TYPE_NAME: &'static str = "Array";
239    const TYPE_NAME_CSTR: &'static [u8] = b"Array\0";
240    const TYPE_ID_CSTR: &'static [u8] = b"std::Array\0";
241}
242// endregion
243
244// region: Static slices
245//
246// `&'static [T]` is Sized (it's a fat pointer: ptr + len, 2 words) and satisfies
247// 'static, so it can be stored directly in ExternalPtr.
248//
249// Use cases:
250// - Const arrays: `static DATA: [i32; 5] = [1, 2, 3, 4, 5]; altrep(&DATA)`
251// - Leaked data: `let leaked: &'static [i32] = Box::leak(vec![1, 2, 3].into_boxed_slice());`
252// - Memory-mapped files with 'static lifetime
253//
254// Note: The data must genuinely live forever. If using Box::leak, the memory
255// is never freed (intentional memory leak for the lifetime of the process).
256
257impl<T: 'static> TypedExternal for &'static [T] {
258    const TYPE_NAME: &'static str = "StaticSlice";
259    const TYPE_NAME_CSTR: &'static [u8] = b"StaticSlice\0";
260    const TYPE_ID_CSTR: &'static [u8] = b"std::StaticSlice\0";
261}
262
263impl<T: 'static> TypedExternal for &'static mut [T] {
264    const TYPE_NAME: &'static str = "StaticMutSlice";
265    const TYPE_NAME_CSTR: &'static [u8] = b"StaticMutSlice\0";
266    const TYPE_ID_CSTR: &'static [u8] = b"std::StaticMutSlice\0";
267}
268// endregion