bones_schema/
lib.rs

1//! Simple reflection system based on the `#[repr(C)]` memory layout.
2//!
3//! You can derive [`HasSchema`] for your Rust types to unlock integration with the `bones_schema`
4//! ecosystem, including `bones_ecs` and `bones_asset`.
5
6#![warn(missing_docs)]
7// This cfg_attr is needed because `rustdoc::all` includes lints not supported on stable
8#![cfg_attr(doc, allow(unknown_lints))]
9#![deny(rustdoc::all)]
10// This allows us to use our stable polyfills for nightly APIs under the same name.
11#![allow(unstable_name_collisions)]
12
13// import the macros if the derive feature is enabled.
14#[cfg(feature = "derive")]
15pub use bones_schema_macros::*;
16
17/// The prelude.
18pub mod prelude {
19    #[cfg(feature = "serde")]
20    pub use crate::ser_de::*;
21    pub use crate::{
22        alloc::{SMap, SVec, SchemaMap, SchemaVec},
23        ptr::*,
24        registry::*,
25        schema::*,
26    };
27    #[cfg(feature = "derive")]
28    pub use bones_schema_macros::*;
29    pub use bones_utils;
30}
31
32mod schema;
33pub use schema::*;
34
35pub mod alloc;
36pub mod ptr;
37pub mod raw_fns;
38pub mod registry;
39
40/// Implementations of [`HasSchema`] for standard types.
41mod std_impls;
42
43/// Serde implementations for [`Schema`].
44#[cfg(feature = "serde")]
45pub mod ser_de;
46
47#[cfg(test)]
48mod test {
49    #[cfg(feature = "derive")]
50    mod derive_test {
51        #![allow(dead_code)]
52
53        use crate::prelude::*;
54
55        #[derive(HasSchema, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Debug)]
56        #[schema_module(crate)]
57        #[repr(C, u8)]
58        pub enum Maybe<T> {
59            /// The value is not set.
60            #[default]
61            Unset,
62            /// The value is set.
63            Set(T),
64        }
65
66        #[derive(HasSchema, Clone, Copy, Debug, PartialEq, Eq, Default)]
67        #[schema_module(crate)]
68        #[repr(u8)]
69        pub enum E {
70            #[default]
71            None,
72            L,
73            R,
74            U,
75            D,
76            G,
77            S,
78        }
79
80        /// Represents the ball in the game
81        #[derive(HasSchema, Clone, Default)]
82        #[schema_module(crate)]
83        pub struct A {
84            pub c: Maybe<u32>,
85            pub d: SVec<u64>,
86            pub e: Maybe<u64>,
87            pub f: u32,
88            pub g: f32,
89            pub h: f32,
90            pub i: E,
91            pub j: u32,
92            pub k: u32,
93        }
94
95        #[derive(HasSchema, Clone, Default)]
96        #[schema_module(crate)]
97        #[repr(C)]
98        pub struct B {
99            pub c: Maybe<u32>,
100            pub d: SVec<u64>,
101            pub e: Maybe<u64>,
102            pub f: u32,
103            pub g: f32,
104            pub h: f32,
105            pub i: E,
106            pub j: u32,
107            pub k: u32,
108        }
109
110        #[derive(HasSchema, Clone, Default)]
111        #[schema_module(crate)]
112        pub struct C {
113            pub c: Maybe<u32>,
114            pub e: Maybe<u64>,
115        }
116
117        #[derive(HasSchema, Clone, Default)]
118        #[schema_module(crate)]
119        #[repr(C)]
120        pub struct D {
121            pub c: Maybe<u32>,
122            pub e: Maybe<u64>,
123        }
124
125        #[derive(HasSchema, Clone)]
126        #[schema(no_default)]
127        #[schema_module(crate)]
128        #[repr(C)]
129        struct F<T> {
130            a: bool,
131            b: T,
132        }
133
134        /// Makes sure that the layout reported in the schema for a generic type matches the layout
135        /// reported by Rust, for two different type parameters.
136        #[test]
137        fn generic_type_schema_layouts_match() {
138            assert_eq!(
139                Maybe::<u32>::schema().layout(),
140                std::alloc::Layout::new::<Maybe<u32>>()
141            );
142            assert_eq!(
143                Maybe::<u64>::schema().layout(),
144                std::alloc::Layout::new::<Maybe<u64>>()
145            );
146            assert_eq!(
147                F::<u64>::schema().layout(),
148                std::alloc::Layout::new::<F<u64>>()
149            );
150            assert_eq!(
151                F::<u32>::schema().layout(),
152                std::alloc::Layout::new::<F<u32>>()
153            );
154
155            // Check a normal enum too, just in case.
156            assert_eq!(E::schema().layout(), std::alloc::Layout::new::<E>());
157        }
158
159        // Makes sure that the layout reported for two structs, where the only difference between
160        // them is the `#[repr(C)]` annotation, matches.
161        #[test]
162        fn schema_layout_for_repr_c_matches_repr_rust() {
163            assert_eq!(A::schema().layout(), B::schema().layout());
164            assert_eq!(C::schema().layout(), D::schema().layout());
165        }
166    }
167}