facet_core/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2// Enable portable_simd when available (detected via autocfg in build.rs)
3#![cfg_attr(has_portable_simd, feature(portable_simd))]
4#![warn(missing_docs)]
5#![warn(clippy::std_instead_of_core)]
6#![warn(clippy::std_instead_of_alloc)]
7// Allow uncommon unicode in the 𝟋 prelude module
8#![allow(uncommon_codepoints)]
9#![doc = include_str!("../README.md")]
10
11#[cfg(feature = "alloc")]
12extern crate alloc;
13
14// Core type definitions (merged from facet-core-types)
15mod types;
16pub use types::*;
17
18// Write trait for serializers
19mod write;
20pub use write::Write;
21
22// Implementations of the Shape trait
23mod impls;
24
25/// Allows querying the [`Shape`] of a type, which in turn lets us inspect any fields, build a value of
26/// this type progressively, etc.
27///
28/// The `'facet` lifetime allows `Facet` to be derived for types that borrow from something else.
29///
30/// # Safety
31///
32/// If you implement this wrong, all the safe abstractions in `facet-reflect`,
33/// all the serializers, deserializers, the entire ecosystem is unsafe.
34///
35/// You're responsible for describing the type layout properly, and annotating all the invariants.
36pub unsafe trait Facet<'facet>: 'facet {
37    /// The shape of this type, including: whether it's a Struct, an Enum, something else?
38    ///
39    /// All its fields, with their names, types, attributes, doc comments, etc.
40    /// VTables for list operations, set operations, map operations, option operations,
41    /// and implementations for Display, Debug, etc.—marker traits like Send, Sync, Copy, Eq,
42    /// and probably other things I'm forgetting.
43    const SHAPE: &'static Shape;
44}
45
46/// Returns the shape of a type as a function pointer.
47///
48/// This is a helper for lazy shape initialization in field definitions.
49/// Using a function pointer instead of a direct reference moves const
50/// evaluation from compile time to runtime, improving compile times.
51///
52/// # Example
53///
54/// ```ignore
55/// use facet_core::{FieldBuilder, shape_of};
56///
57/// // In field definitions:
58/// FieldBuilder::new("my_field", shape_of::<i32>, 0)
59/// ```
60#[inline]
61pub fn shape_of<'a, T: Facet<'a>>() -> &'static Shape {
62    T::SHAPE
63}
64
65/// Ultra-compact prelude for derive macro codegen (the "digamma" prelude).
66///
67/// All exports are prefixed with `𝟋` to avoid collisions after `use ::facet::𝟋::*;`
68///
69/// The `𝟋` character (U+1D4CB, Mathematical Script Small F, "digamma") was chosen because:
70/// - It's a valid Rust identifier (XID_Start)
71/// - It's visually distinctive ("this is internal macro stuff")
72/// - It won't collide with any user-defined names
73#[doc(hidden)]
74#[allow(nonstandard_style)]
75pub mod 𝟋 {
76    // === Type aliases ===
77    pub use crate::Attr as 𝟋Attr;
78    pub use crate::Def as 𝟋Def;
79    pub use crate::DefaultSource as 𝟋DS;
80    pub use crate::EnumRepr as 𝟋ERpr;
81    pub use crate::EnumType as 𝟋ETy;
82    pub use crate::EnumTypeBuilder as 𝟋ETyB;
83    pub use crate::Facet as 𝟋Fct;
84    pub use crate::Field as 𝟋Fld;
85    pub use crate::FieldBuilder as 𝟋FldB;
86    pub use crate::FieldFlags as 𝟋FF;
87    pub use crate::HashProxy as 𝟋HP;
88    pub use crate::MarkerTraits as 𝟋Mt;
89    pub use crate::Repr as 𝟋Repr;
90    pub use crate::Shape as 𝟋Shp;
91    pub use crate::ShapeBuilder as 𝟋ShpB;
92    pub use crate::ShapeFlags as 𝟋ShpF;
93    pub use crate::ShapeRef as 𝟋ShpR;
94    pub use crate::StructKind as 𝟋Sk;
95    pub use crate::StructType as 𝟋STy;
96    pub use crate::StructTypeBuilder as 𝟋STyB;
97    pub use crate::Type as 𝟋Ty;
98    pub use crate::UserType as 𝟋UTy;
99    pub use crate::VTableDirect as 𝟋VtD;
100    pub use crate::VTableErased as 𝟋VtE;
101    pub use crate::Variance as 𝟋Vnc;
102    pub use crate::Variant as 𝟋Var;
103    pub use crate::VariantBuilder as 𝟋VarB;
104
105    /// Helper to get shape of a type as a function - monomorphized per type
106    pub use crate::shape_of as 𝟋shp;
107
108    // === Constants ===
109    /// Empty attributes slice
110    pub const 𝟋NOAT: &[crate::FieldAttribute] = &[];
111    /// Empty doc slice
112    pub const 𝟋NODOC: &[&str] = &[];
113    /// Empty flags
114    pub const 𝟋NOFL: crate::FieldFlags = crate::FieldFlags::empty();
115    /// Computed variance function (for non-opaque types)
116    pub const 𝟋CV: fn(&'static crate::Shape) -> crate::Variance = crate::Shape::computed_variance;
117
118    // === Type Aliases ===
119    /// PhantomData type for shadow structs, invariant in lifetime `'a`.
120    pub type 𝟋Ph<'a> = ::core::marker::PhantomData<*mut &'a ()>;
121
122    /// String type for proxy conversion errors (requires alloc feature).
123    #[cfg(feature = "alloc")]
124    pub type 𝟋Str = ::alloc::string::String;
125
126    /// Fallback when alloc is not available - proxy requires alloc at runtime,
127    /// but we need a type for compilation in no_std contexts.
128    #[cfg(not(feature = "alloc"))]
129    pub type 𝟋Str = &'static str;
130
131    /// Result type alias for macro-generated code.
132    pub type 𝟋Result<T, E> = ::core::result::Result<T, E>;
133
134    // === Helper functions ===
135    /// Returns `drop_in_place::<T>` as a function pointer for vtable construction.
136    pub const fn 𝟋drop_for<T>() -> unsafe fn(*mut T) {
137        ::core::ptr::drop_in_place::<T>
138    }
139
140    /// Returns a default_in_place function pointer for TypeOpsDirect.
141    /// # Safety
142    /// The pointer must point to uninitialized memory of sufficient size and alignment for T.
143    pub const fn 𝟋default_for<T: Default>() -> unsafe fn(*mut T) {
144        unsafe fn default_in_place<T: Default>(ptr: *mut T) {
145            unsafe { ptr.write(T::default()) };
146        }
147        default_in_place::<T>
148    }
149
150    /// Returns a clone_into function pointer for TypeOpsDirect.
151    /// # Safety
152    /// - `src` must point to a valid, initialized value of type T
153    /// - `dst` must point to uninitialized memory of sufficient size and alignment for T
154    pub const fn 𝟋clone_for<T: Clone>() -> unsafe fn(*const T, *mut T) {
155        unsafe fn clone_into<T: Clone>(src: *const T, dst: *mut T) {
156            unsafe { dst.write((*src).clone()) };
157        }
158        clone_into::<T>
159    }
160
161    // === TypeOpsIndirect helpers ===
162    // These take OxPtrMut/OxPtrConst and work with wide pointers
163
164    /// Returns a drop_in_place function pointer for TypeOpsIndirect.
165    pub const fn 𝟋indirect_drop_for<T>() -> unsafe fn(crate::OxPtrMut) {
166        unsafe fn drop_in_place<T>(ox: crate::OxPtrMut) {
167            unsafe { ::core::ptr::drop_in_place(ox.ptr().as_ptr::<T>() as *mut T) };
168        }
169        drop_in_place::<T>
170    }
171
172    /// Returns a default_in_place function pointer for TypeOpsIndirect.
173    pub const fn 𝟋indirect_default_for<T: Default>() -> unsafe fn(crate::OxPtrMut) {
174        unsafe fn default_in_place<T: Default>(ox: crate::OxPtrMut) {
175            unsafe { ox.ptr().as_uninit().put(T::default()) };
176        }
177        default_in_place::<T>
178    }
179
180    /// Returns a clone_into function pointer for TypeOpsIndirect.
181    pub const fn 𝟋indirect_clone_for<T: Clone>() -> unsafe fn(crate::OxPtrConst, crate::OxPtrMut) {
182        unsafe fn clone_into<T: Clone>(src: crate::OxPtrConst, dst: crate::OxPtrMut) {
183            let src_val = unsafe { &*(src.ptr().as_byte_ptr() as *const T) };
184            unsafe { dst.ptr().as_uninit().put(src_val.clone()) };
185        }
186        clone_into::<T>
187    }
188
189    // === Specialization ===
190    pub use crate::types::specialization::impls;
191    pub use crate::types::specialization::{
192        Spez, SpezCloneIntoNo, SpezCloneIntoYes, SpezDebugNo, SpezDebugYes, SpezDefaultInPlaceNo,
193        SpezDefaultInPlaceYes, SpezDisplayNo, SpezDisplayYes, SpezEmpty, SpezHashNo, SpezHashYes,
194        SpezOrdNo, SpezOrdYes, SpezParseNo, SpezParseYes, SpezPartialEqNo, SpezPartialEqYes,
195        SpezPartialOrdNo, SpezPartialOrdYes,
196    };
197}