Allow providing CustomInternalSchemaData instead of only adding data for
forcing as array.
This commit is contained in:
parent
5ad2351c2a
commit
2800e77ef9
@ -1866,12 +1866,12 @@ mod tests {
|
|||||||
|
|
||||||
let atr = AppTypeRegistry::default();
|
let atr = AppTypeRegistry::default();
|
||||||
{
|
{
|
||||||
use crate::schemas::ReflectJsonSchemaForceAsArray;
|
use crate::schemas::RegisterReflectJsonSchemas;
|
||||||
|
|
||||||
let mut register = atr.write();
|
let mut register = atr.write();
|
||||||
register.register::<NestedStruct>();
|
register.register::<NestedStruct>();
|
||||||
register.register::<bevy_math::Vec3>();
|
register.register::<bevy_math::Vec3>();
|
||||||
register.register_type_data::<bevy_math::Vec3, ReflectJsonSchemaForceAsArray>();
|
register.register_force_as_array::<bevy_math::Vec3>();
|
||||||
}
|
}
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
world.insert_resource(atr);
|
world.insert_resource(atr);
|
||||||
|
|||||||
@ -7,12 +7,16 @@ use bevy_ecs::{
|
|||||||
};
|
};
|
||||||
use bevy_platform::collections::HashMap;
|
use bevy_platform::collections::HashMap;
|
||||||
use bevy_reflect::{
|
use bevy_reflect::{
|
||||||
prelude::ReflectDefault, FromType, Reflect, ReflectDeserialize, ReflectSerialize, TypeData,
|
prelude::ReflectDefault, FromType, GetTypeRegistration, Reflect, ReflectDeserialize,
|
||||||
TypeRegistration,
|
ReflectSerialize, TypeData, TypePath, TypeRegistration,
|
||||||
};
|
};
|
||||||
use core::any::TypeId;
|
use core::any::TypeId;
|
||||||
|
|
||||||
use crate::schemas::{json_schema::JsonSchemaBevyType, open_rpc::OpenRpcDocument};
|
use crate::schemas::{
|
||||||
|
json_schema::JsonSchemaBevyType,
|
||||||
|
open_rpc::OpenRpcDocument,
|
||||||
|
reflect_info::{FieldsInformation, InternalSchemaType},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod json_schema;
|
pub mod json_schema;
|
||||||
pub mod open_rpc;
|
pub mod open_rpc;
|
||||||
@ -27,13 +31,23 @@ pub struct SchemaTypesMetadata {
|
|||||||
pub type_data_map: HashMap<TypeId, Cow<'static, str>>,
|
pub type_data_map: HashMap<TypeId, Cow<'static, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reflect-compatible custom JSON Schema for this type
|
/// Custom internal schema data.
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Resource, Reflect, Clone)]
|
||||||
pub struct ReflectJsonSchemaForceAsArray;
|
#[reflect(Resource)]
|
||||||
|
pub struct CustomInternalSchemaData(pub InternalSchemaType);
|
||||||
|
|
||||||
impl<T: Reflect> FromType<T> for ReflectJsonSchemaForceAsArray {
|
impl CustomInternalSchemaData {
|
||||||
fn from_type() -> Self {
|
/// Creates a new `CustomInternalSchema` with a forced array type. Works for structs only.
|
||||||
ReflectJsonSchemaForceAsArray
|
pub fn force_array<T: GetTypeRegistration>() -> Option<Self> {
|
||||||
|
match T::get_type_registration().type_info() {
|
||||||
|
bevy_reflect::TypeInfo::Struct(struct_info) => Some(CustomInternalSchemaData(
|
||||||
|
InternalSchemaType::FieldsHolder(FieldsInformation::new(
|
||||||
|
struct_info.iter(),
|
||||||
|
reflect_info::FieldType::ForceUnnamed,
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,62 +57,76 @@ pub(crate) trait RegisterReflectJsonSchemas {
|
|||||||
fn register_schema_base_types(&mut self) {
|
fn register_schema_base_types(&mut self) {
|
||||||
#[cfg(feature = "bevy_math")]
|
#[cfg(feature = "bevy_math")]
|
||||||
{
|
{
|
||||||
self.register_type_data_internal::<bevy_math::Vec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::Vec2>();
|
||||||
self.register_type_data_internal::<bevy_math::DVec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::DVec2>();
|
||||||
self.register_type_data_internal::<bevy_math::I8Vec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::I8Vec2>();
|
||||||
self.register_type_data_internal::<bevy_math::U8Vec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::U8Vec2>();
|
||||||
self.register_type_data_internal::<bevy_math::I16Vec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::I16Vec2>();
|
||||||
self.register_type_data_internal::<bevy_math::U16Vec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::U16Vec2>();
|
||||||
self.register_type_data_internal::<bevy_math::IVec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::IVec2>();
|
||||||
self.register_type_data_internal::<bevy_math::UVec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::UVec2>();
|
||||||
self.register_type_data_internal::<bevy_math::I64Vec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::I64Vec2>();
|
||||||
self.register_type_data_internal::<bevy_math::U64Vec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::U64Vec2>();
|
||||||
self.register_type_data_internal::<bevy_math::BVec2, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::BVec2>();
|
||||||
|
|
||||||
self.register_type_data_internal::<bevy_math::Vec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::Vec3>();
|
||||||
self.register_type_data_internal::<bevy_math::DVec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::DVec3>();
|
||||||
self.register_type_data_internal::<bevy_math::I8Vec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::I8Vec3>();
|
||||||
self.register_type_data_internal::<bevy_math::U8Vec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::U8Vec3>();
|
||||||
self.register_type_data_internal::<bevy_math::I16Vec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::I16Vec3>();
|
||||||
self.register_type_data_internal::<bevy_math::U16Vec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::U16Vec3>();
|
||||||
self.register_type_data_internal::<bevy_math::IVec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::IVec3>();
|
||||||
self.register_type_data_internal::<bevy_math::UVec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::UVec3>();
|
||||||
self.register_type_data_internal::<bevy_math::I64Vec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::I64Vec3>();
|
||||||
self.register_type_data_internal::<bevy_math::U64Vec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::U64Vec3>();
|
||||||
self.register_type_data_internal::<bevy_math::BVec3, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::BVec3>();
|
||||||
|
|
||||||
self.register_type_data_internal::<bevy_math::Vec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::Vec4>();
|
||||||
self.register_type_data_internal::<bevy_math::DVec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::DVec4>();
|
||||||
self.register_type_data_internal::<bevy_math::I8Vec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::I8Vec4>();
|
||||||
self.register_type_data_internal::<bevy_math::U8Vec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::U8Vec4>();
|
||||||
self.register_type_data_internal::<bevy_math::I16Vec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::I16Vec4>();
|
||||||
self.register_type_data_internal::<bevy_math::U16Vec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::U16Vec4>();
|
||||||
self.register_type_data_internal::<bevy_math::IVec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::IVec4>();
|
||||||
self.register_type_data_internal::<bevy_math::UVec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::UVec4>();
|
||||||
self.register_type_data_internal::<bevy_math::I64Vec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::I64Vec4>();
|
||||||
self.register_type_data_internal::<bevy_math::U64Vec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::U64Vec4>();
|
||||||
self.register_type_data_internal::<bevy_math::BVec4, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::BVec4>();
|
||||||
|
|
||||||
self.register_type_data_internal::<bevy_math::Quat, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::Quat>();
|
||||||
self.register_type_data_internal::<bevy_math::DQuat, ReflectJsonSchemaForceAsArray>();
|
self.register_force_as_array::<bevy_math::DQuat>();
|
||||||
}
|
}
|
||||||
self.register_type_internal::<OpenRpcDocument>();
|
self.register_type_internal::<OpenRpcDocument>();
|
||||||
self.register_type_data_internal::<OpenRpcDocument, ReflectJsonSchema>();
|
self.register_type_data_internal::<OpenRpcDocument, ReflectJsonSchema>();
|
||||||
}
|
}
|
||||||
|
/// Registers a type by value.
|
||||||
|
fn register_data_type_by_value<T, D>(&mut self, data: D)
|
||||||
|
where
|
||||||
|
T: Reflect + TypePath + GetTypeRegistration,
|
||||||
|
D: TypeData;
|
||||||
fn register_type_internal<T>(&mut self)
|
fn register_type_internal<T>(&mut self)
|
||||||
where
|
where
|
||||||
T: bevy_reflect::GetTypeRegistration;
|
T: GetTypeRegistration;
|
||||||
|
|
||||||
fn register_type_data_internal<T, D>(&mut self)
|
fn register_type_data_internal<T, D>(&mut self)
|
||||||
where
|
where
|
||||||
T: Reflect + bevy_reflect::TypePath + bevy_reflect::GetTypeRegistration,
|
T: Reflect + TypePath + GetTypeRegistration,
|
||||||
D: TypeData + FromType<T>;
|
D: TypeData + FromType<T>;
|
||||||
|
fn register_force_as_array<T>(&mut self)
|
||||||
|
where
|
||||||
|
T: Reflect + TypePath + GetTypeRegistration,
|
||||||
|
{
|
||||||
|
let Some(data) = CustomInternalSchemaData::force_array::<T>() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.register_data_type_by_value::<T, CustomInternalSchemaData>(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterReflectJsonSchemas for bevy_reflect::TypeRegistry {
|
impl RegisterReflectJsonSchemas for bevy_reflect::TypeRegistry {
|
||||||
fn register_type_data_internal<T, D>(&mut self)
|
fn register_type_data_internal<T, D>(&mut self)
|
||||||
where
|
where
|
||||||
T: Reflect + bevy_reflect::TypePath + bevy_reflect::GetTypeRegistration,
|
T: Reflect + TypePath + GetTypeRegistration,
|
||||||
D: TypeData + FromType<T>,
|
D: TypeData + FromType<T>,
|
||||||
{
|
{
|
||||||
if !self.contains(TypeId::of::<T>()) {
|
if !self.contains(TypeId::of::<T>()) {
|
||||||
@ -109,15 +137,25 @@ impl RegisterReflectJsonSchemas for bevy_reflect::TypeRegistry {
|
|||||||
|
|
||||||
fn register_type_internal<T>(&mut self)
|
fn register_type_internal<T>(&mut self)
|
||||||
where
|
where
|
||||||
T: bevy_reflect::GetTypeRegistration,
|
T: GetTypeRegistration,
|
||||||
{
|
{
|
||||||
self.register::<T>();
|
self.register::<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_data_type_by_value<T, D>(&mut self, data: D)
|
||||||
|
where
|
||||||
|
T: Reflect + TypePath + GetTypeRegistration,
|
||||||
|
D: TypeData,
|
||||||
|
{
|
||||||
|
self.get_mut(TypeId::of::<T>())
|
||||||
|
.expect("SHOULD NOT HAPPENED")
|
||||||
|
.insert(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl RegisterReflectJsonSchemas for bevy_app::App {
|
impl RegisterReflectJsonSchemas for bevy_app::App {
|
||||||
fn register_type_data_internal<T, D>(&mut self)
|
fn register_type_data_internal<T, D>(&mut self)
|
||||||
where
|
where
|
||||||
T: Reflect + bevy_reflect::TypePath + bevy_reflect::GetTypeRegistration,
|
T: Reflect + TypePath + GetTypeRegistration,
|
||||||
D: TypeData + FromType<T>,
|
D: TypeData + FromType<T>,
|
||||||
{
|
{
|
||||||
self.register_type::<T>();
|
self.register_type::<T>();
|
||||||
@ -126,10 +164,22 @@ impl RegisterReflectJsonSchemas for bevy_app::App {
|
|||||||
|
|
||||||
fn register_type_internal<T>(&mut self)
|
fn register_type_internal<T>(&mut self)
|
||||||
where
|
where
|
||||||
T: bevy_reflect::GetTypeRegistration,
|
T: GetTypeRegistration,
|
||||||
{
|
{
|
||||||
self.register_type::<T>();
|
self.register_type::<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_data_type_by_value<T, D>(&mut self, data: D)
|
||||||
|
where
|
||||||
|
T: Reflect + TypePath + GetTypeRegistration,
|
||||||
|
D: TypeData,
|
||||||
|
{
|
||||||
|
let sub_app = self.main_mut();
|
||||||
|
let world = sub_app.world_mut();
|
||||||
|
let registry = world.resource_mut::<bevy_ecs::reflect::AppTypeRegistry>();
|
||||||
|
let mut r = registry.write();
|
||||||
|
r.register_data_type_by_value::<T, D>(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reflect-compatible custom JSON Schema for this type
|
/// Reflect-compatible custom JSON Schema for this type
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
use crate::schemas::json_schema::{
|
use crate::schemas::json_schema::{
|
||||||
JsonSchemaBevyType, JsonSchemaVariant, SchemaKind, SchemaType, SchemaTypeVariant,
|
JsonSchemaBevyType, JsonSchemaVariant, SchemaKind, SchemaType, SchemaTypeVariant,
|
||||||
};
|
};
|
||||||
use crate::schemas::{ReflectJsonSchemaForceAsArray, SchemaTypesMetadata};
|
use crate::schemas::{CustomInternalSchemaData, SchemaTypesMetadata};
|
||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
@ -298,8 +298,8 @@ impl From<&TypePathTable> for TypeReferenceId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Information about the field type.
|
/// Information about the field type.
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default, Reflect)]
|
||||||
pub(crate) enum FieldType {
|
pub enum FieldType {
|
||||||
/// Named field type.
|
/// Named field type.
|
||||||
Named,
|
Named,
|
||||||
/// Unnamed field type.
|
/// Unnamed field type.
|
||||||
@ -310,8 +310,8 @@ pub(crate) enum FieldType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Information about the attributes of a field.
|
/// Information about the attributes of a field.
|
||||||
#[derive(Clone, Debug, Deref, DerefMut, Default)]
|
#[derive(Clone, Debug, Deref, DerefMut, Default, Reflect)]
|
||||||
pub(crate) struct FieldsInformation {
|
pub struct FieldsInformation {
|
||||||
/// Fields information.
|
/// Fields information.
|
||||||
#[deref]
|
#[deref]
|
||||||
fields: Vec<SchemaFieldData>,
|
fields: Vec<SchemaFieldData>,
|
||||||
@ -319,6 +319,19 @@ pub(crate) struct FieldsInformation {
|
|||||||
fields_type: FieldType,
|
fields_type: FieldType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FieldsInformation {
|
||||||
|
/// Creates a new instance of `FieldsInformation`.
|
||||||
|
pub fn new<'a, 'b, T>(iterator: Iter<'a, T>, fields_type: FieldType) -> Self
|
||||||
|
where
|
||||||
|
SchemaFieldData: From<&'a T>,
|
||||||
|
{
|
||||||
|
FieldsInformation {
|
||||||
|
fields: get_fields_information(iterator),
|
||||||
|
fields_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deref)]
|
#[derive(Clone, Debug, Deref)]
|
||||||
/// Information about the attributes of a field.
|
/// Information about the attributes of a field.
|
||||||
pub(crate) struct AttributesInformation(Arc<TypeIdMap<Box<dyn Reflect>>>);
|
pub(crate) struct AttributesInformation(Arc<TypeIdMap<Box<dyn Reflect>>>);
|
||||||
@ -385,30 +398,20 @@ fn try_get_regex_for_type(id: TypeId) -> Option<Cow<'static, str>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the data of a field in a schema.
|
/// Represents the data of a field in a schema.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Reflect, Debug)]
|
||||||
pub(crate) struct SchemaFieldData {
|
pub struct SchemaFieldData {
|
||||||
/// Name of the field.
|
/// Name of the field.
|
||||||
pub name: Option<Cow<'static, str>>,
|
pub name: Option<Cow<'static, str>>,
|
||||||
/// Index of the field. Can be provided for named fields when the data is obtained from containing struct definition.
|
/// Index of the field. Can be provided for named fields when the data is obtained from containing struct definition.
|
||||||
pub index: Option<usize>,
|
pub index: Option<usize>,
|
||||||
/// Description of the field.
|
/// Description of the field.
|
||||||
pub description: Option<Cow<'static, str>>,
|
pub description: Option<Cow<'static, str>>,
|
||||||
/// Attributes of the field.
|
/// Custom of the field.
|
||||||
pub attributes: AttributesInformation,
|
pub range: Option<MinMaxValues>,
|
||||||
/// Type of the field.
|
/// Type of the field.
|
||||||
pub type_id: TypeId,
|
pub type_id: TypeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for SchemaFieldData {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("SchemaFieldData")
|
|
||||||
.field("name", &self.name)
|
|
||||||
.field("index", &self.index)
|
|
||||||
.field("description", &self.description)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SchemaFieldData {
|
impl SchemaFieldData {
|
||||||
/// Returns the name of the field.
|
/// Returns the name of the field.
|
||||||
pub fn to_name(&self) -> Cow<'static, str> {
|
pub fn to_name(&self) -> Cow<'static, str> {
|
||||||
@ -810,11 +813,28 @@ impl From<TypeId> for MinMaxValues {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Enum representing the internal schema type information for different Rust types.
|
||||||
|
#[derive(Clone, Debug, Reflect)]
|
||||||
|
pub enum SchemaEnumType {
|
||||||
|
/// Represents a constant value.
|
||||||
|
Const,
|
||||||
|
/// Represents a set of fields with their respective types.
|
||||||
|
Fields(FieldsInformation),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a variant of an enum type.
|
||||||
|
#[derive(Clone, Debug, Reflect)]
|
||||||
|
pub struct EnumVariantInfo {
|
||||||
|
/// Field data for the enum variant.
|
||||||
|
pub field_data: SchemaFieldData,
|
||||||
|
/// Information about the enum variant.
|
||||||
|
pub info: SchemaEnumType,
|
||||||
|
}
|
||||||
|
|
||||||
/// Enum representing the internal schema type information for different Rust types.
|
/// Enum representing the internal schema type information for different Rust types.
|
||||||
/// This enum categorizes how different types should be represented in JSON schema.
|
/// This enum categorizes how different types should be represented in JSON schema.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Reflect)]
|
||||||
pub(crate) enum InternalSchemaType {
|
pub enum InternalSchemaType {
|
||||||
/// Represents array-like types (Vec, arrays, lists, sets).
|
/// Represents array-like types (Vec, arrays, lists, sets).
|
||||||
Array {
|
Array {
|
||||||
/// Element type information for the array.
|
/// Element type information for the array.
|
||||||
@ -825,13 +845,13 @@ pub(crate) enum InternalSchemaType {
|
|||||||
max_size: Option<u64>,
|
max_size: Option<u64>,
|
||||||
},
|
},
|
||||||
/// Holds all variants of an enum type.
|
/// Holds all variants of an enum type.
|
||||||
EnumHolder(Vec<VariantInfo>),
|
EnumHolder(Vec<EnumVariantInfo>),
|
||||||
/// Holds named fields for struct, tuple, and tuple struct types.
|
/// Holds named fields for struct, tuple, and tuple struct types.
|
||||||
FieldsHolder(FieldsInformation),
|
FieldsHolder(FieldsInformation),
|
||||||
/// Represents an Optional type (e.g., `Option<T>`).
|
/// Represents an Optional type (e.g., `Option<T>`).
|
||||||
Optional {
|
Optional {
|
||||||
/// Generic information about the wrapped type `T` in `Option<T>`.
|
/// Type information for the wrapped type `T` in `Option<T>`.
|
||||||
generic: GenericInfo,
|
generic: TypeId,
|
||||||
},
|
},
|
||||||
/// Represents a Map type (e.g., `HashMap`<K, V>).
|
/// Represents a Map type (e.g., `HashMap`<K, V>).
|
||||||
Map {
|
Map {
|
||||||
@ -867,6 +887,9 @@ impl InternalSchemaType {
|
|||||||
value: &TypeRegistration,
|
value: &TypeRegistration,
|
||||||
registry: &TypeRegistry,
|
registry: &TypeRegistry,
|
||||||
) -> InternalSchemaType {
|
) -> InternalSchemaType {
|
||||||
|
if let Some(data) = value.data::<CustomInternalSchemaData>() {
|
||||||
|
return data.0.clone();
|
||||||
|
}
|
||||||
if let Some(primitive) =
|
if let Some(primitive) =
|
||||||
SchemaType::try_get_primitive_type_from_type_id(value.type_info().type_id())
|
SchemaType::try_get_primitive_type_from_type_id(value.type_info().type_id())
|
||||||
{
|
{
|
||||||
@ -879,14 +902,9 @@ impl InternalSchemaType {
|
|||||||
match value.type_info() {
|
match value.type_info() {
|
||||||
TypeInfo::Struct(struct_info) => {
|
TypeInfo::Struct(struct_info) => {
|
||||||
let fields = get_fields_information(struct_info.iter());
|
let fields = get_fields_information(struct_info.iter());
|
||||||
let fields_type = if value.data::<ReflectJsonSchemaForceAsArray>().is_some() {
|
|
||||||
FieldType::ForceUnnamed
|
|
||||||
} else {
|
|
||||||
FieldType::Named
|
|
||||||
};
|
|
||||||
InternalSchemaType::FieldsHolder(FieldsInformation {
|
InternalSchemaType::FieldsHolder(FieldsInformation {
|
||||||
fields,
|
fields,
|
||||||
fields_type,
|
fields_type: FieldType::Named,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
TypeInfo::TupleStruct(info) => {
|
TypeInfo::TupleStruct(info) => {
|
||||||
@ -916,8 +934,10 @@ impl InternalSchemaType {
|
|||||||
fields_type: FieldType::Unnamed,
|
fields_type: FieldType::Unnamed,
|
||||||
}),
|
}),
|
||||||
TypeInfo::Enum(enum_info) => match enum_info.try_get_optional() {
|
TypeInfo::Enum(enum_info) => match enum_info.try_get_optional() {
|
||||||
Some(e) => InternalSchemaType::Optional { generic: e.clone() },
|
Some(e) => InternalSchemaType::Optional {
|
||||||
None => InternalSchemaType::EnumHolder(enum_info.iter().cloned().collect()),
|
generic: e.ty().id(),
|
||||||
|
},
|
||||||
|
None => InternalSchemaType::EnumHolder(get_enum_information(enum_info.iter())),
|
||||||
},
|
},
|
||||||
|
|
||||||
TypeInfo::List(list_info) => InternalSchemaType::Array {
|
TypeInfo::List(list_info) => InternalSchemaType::Array {
|
||||||
@ -960,23 +980,15 @@ impl InternalSchemaType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
InternalSchemaType::EnumHolder(variant_infos) => {
|
InternalSchemaType::EnumHolder(variant_infos) => {
|
||||||
for variant_info in variant_infos {
|
for variant_info in variant_infos.iter() {
|
||||||
let subschema = match variant_info {
|
let variant_dependencies = match &variant_info.info {
|
||||||
VariantInfo::Struct(struct_variant_info) => {
|
SchemaEnumType::Const => continue,
|
||||||
InternalSchemaType::FieldsHolder(FieldsInformation {
|
SchemaEnumType::Fields(fields_information) => {
|
||||||
fields: get_fields_information(struct_variant_info.iter()),
|
InternalSchemaType::FieldsHolder(fields_information.clone())
|
||||||
fields_type: FieldType::Named,
|
.get_dependencies(registry)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
VariantInfo::Tuple(tuple_variant_info) => {
|
|
||||||
InternalSchemaType::FieldsHolder(FieldsInformation {
|
|
||||||
fields: get_fields_information(tuple_variant_info.iter()),
|
|
||||||
fields_type: FieldType::Unnamed,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
VariantInfo::Unit(_) => continue,
|
|
||||||
};
|
};
|
||||||
dependencies.extend(subschema.get_dependencies(registry));
|
dependencies.extend(variant_dependencies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InternalSchemaType::FieldsHolder(fields_information) => {
|
InternalSchemaType::FieldsHolder(fields_information) => {
|
||||||
@ -995,7 +1007,7 @@ impl InternalSchemaType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
InternalSchemaType::Optional { generic } => {
|
InternalSchemaType::Optional { generic } => {
|
||||||
if let Some(reg) = registry.get(generic.type_id()) {
|
if let Some(reg) = registry.get(*generic) {
|
||||||
if SchemaType::try_get_primitive_type_from_type_id(reg.type_id()).is_none() {
|
if SchemaType::try_get_primitive_type_from_type_id(reg.type_id()).is_none() {
|
||||||
let subschema = InternalSchemaType::from_type_registration(reg, registry);
|
let subschema = InternalSchemaType::from_type_registration(reg, registry);
|
||||||
if !subschema.is_optional() {
|
if !subschema.is_optional() {
|
||||||
@ -1157,13 +1169,13 @@ pub trait AttributeInfoReflect {
|
|||||||
|
|
||||||
impl From<&UnnamedField> for SchemaFieldData {
|
impl From<&UnnamedField> for SchemaFieldData {
|
||||||
fn from(value: &UnnamedField) -> Self {
|
fn from(value: &UnnamedField) -> Self {
|
||||||
let attributes: AttributesInformation = value.custom_attributes().into();
|
let range = value.custom_attributes().get_range_by_id(value.type_id());
|
||||||
#[cfg(feature = "documentation")]
|
#[cfg(feature = "documentation")]
|
||||||
let description = value.docs().map(|s| Cow::Owned(s.to_owned()));
|
let description = value.docs().map(|s| Cow::Owned(s.to_owned()));
|
||||||
#[cfg(not(feature = "documentation"))]
|
#[cfg(not(feature = "documentation"))]
|
||||||
let description = None;
|
let description = None;
|
||||||
SchemaFieldData {
|
SchemaFieldData {
|
||||||
attributes,
|
range,
|
||||||
name: None,
|
name: None,
|
||||||
index: Some(value.index()),
|
index: Some(value.index()),
|
||||||
description,
|
description,
|
||||||
@ -1173,7 +1185,7 @@ impl From<&UnnamedField> for SchemaFieldData {
|
|||||||
}
|
}
|
||||||
impl From<&NamedField> for SchemaFieldData {
|
impl From<&NamedField> for SchemaFieldData {
|
||||||
fn from(value: &NamedField) -> Self {
|
fn from(value: &NamedField) -> Self {
|
||||||
let attributes: AttributesInformation = value.custom_attributes().into();
|
let range = value.custom_attributes().get_range_by_id(value.type_id());
|
||||||
#[cfg(feature = "documentation")]
|
#[cfg(feature = "documentation")]
|
||||||
let description = value.docs().map(|s| Cow::Owned(s.to_owned()));
|
let description = value.docs().map(|s| Cow::Owned(s.to_owned()));
|
||||||
#[cfg(not(feature = "documentation"))]
|
#[cfg(not(feature = "documentation"))]
|
||||||
@ -1182,7 +1194,7 @@ impl From<&NamedField> for SchemaFieldData {
|
|||||||
name: Some(value.name().into()),
|
name: Some(value.name().into()),
|
||||||
index: None,
|
index: None,
|
||||||
description,
|
description,
|
||||||
attributes,
|
range,
|
||||||
type_id: value.type_id(),
|
type_id: value.type_id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1190,6 +1202,7 @@ impl From<&NamedField> for SchemaFieldData {
|
|||||||
|
|
||||||
impl From<&VariantInfo> for SchemaFieldData {
|
impl From<&VariantInfo> for SchemaFieldData {
|
||||||
fn from(value: &VariantInfo) -> Self {
|
fn from(value: &VariantInfo) -> Self {
|
||||||
|
let range = value.custom_attributes().get_range_by_id(value.type_id());
|
||||||
#[cfg(feature = "documentation")]
|
#[cfg(feature = "documentation")]
|
||||||
let description = value.docs().map(|s| Cow::Owned(s.to_owned()));
|
let description = value.docs().map(|s| Cow::Owned(s.to_owned()));
|
||||||
#[cfg(not(feature = "documentation"))]
|
#[cfg(not(feature = "documentation"))]
|
||||||
@ -1198,12 +1211,38 @@ impl From<&VariantInfo> for SchemaFieldData {
|
|||||||
name: Some(value.name().to_owned().into()),
|
name: Some(value.name().to_owned().into()),
|
||||||
index: None,
|
index: None,
|
||||||
description,
|
description,
|
||||||
attributes: value.custom_attributes().into(),
|
range,
|
||||||
type_id: value.type_id(),
|
type_id: value.type_id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_enum_information<'a>(iterator: Iter<'a, VariantInfo>) -> Vec<EnumVariantInfo> {
|
||||||
|
iterator
|
||||||
|
.map(|variant| {
|
||||||
|
let info = match variant {
|
||||||
|
VariantInfo::Struct(struct_variant_info) => {
|
||||||
|
SchemaEnumType::Fields(FieldsInformation {
|
||||||
|
fields: get_fields_information(struct_variant_info.iter()),
|
||||||
|
fields_type: FieldType::Named,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
VariantInfo::Tuple(tuple_variant_info) => {
|
||||||
|
SchemaEnumType::Fields(FieldsInformation {
|
||||||
|
fields: get_fields_information(tuple_variant_info.iter()),
|
||||||
|
fields_type: FieldType::Unnamed,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
VariantInfo::Unit(_) => SchemaEnumType::Const,
|
||||||
|
};
|
||||||
|
EnumVariantInfo {
|
||||||
|
info,
|
||||||
|
field_data: variant.into(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_fields_information<'a, 'b, T>(iterator: Iter<'a, T>) -> Vec<SchemaFieldData>
|
fn get_fields_information<'a, 'b, T>(iterator: Iter<'a, T>) -> Vec<SchemaFieldData>
|
||||||
where
|
where
|
||||||
SchemaFieldData: From<&'a T>,
|
SchemaFieldData: From<&'a T>,
|
||||||
@ -1218,36 +1257,29 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn variant_to_definition(
|
pub(crate) fn variant_to_definition(
|
||||||
variant: &VariantInfo,
|
variant: &EnumVariantInfo,
|
||||||
registry: &TypeRegistry,
|
registry: &TypeRegistry,
|
||||||
) -> JsonSchemaBevyType {
|
) -> JsonSchemaBevyType {
|
||||||
let field_data: SchemaFieldData = variant.into();
|
|
||||||
let mut schema = JsonSchemaBevyType {
|
let mut schema = JsonSchemaBevyType {
|
||||||
description: field_data.to_description(),
|
description: variant.field_data.to_description(),
|
||||||
kind: Some(SchemaKind::Value),
|
kind: Some(SchemaKind::Value),
|
||||||
schema_type: Some(SchemaTypeVariant::Single(SchemaType::Object)),
|
schema_type: Some(SchemaTypeVariant::Single(SchemaType::Object)),
|
||||||
additional_properties: Some(JsonSchemaVariant::BoolValue(false)),
|
additional_properties: Some(JsonSchemaVariant::BoolValue(false)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let fields_info = match variant {
|
let name = variant.field_data.name.as_ref().expect("").to_string();
|
||||||
VariantInfo::Unit(unit_variant_info) => {
|
let fields_info = match &variant.info {
|
||||||
schema.const_value = Some(unit_variant_info.name().to_string().into());
|
SchemaEnumType::Const => {
|
||||||
|
schema.const_value = Some(name.into());
|
||||||
schema.schema_type = Some(SchemaTypeVariant::Single(SchemaType::String));
|
schema.schema_type = Some(SchemaTypeVariant::Single(SchemaType::String));
|
||||||
schema.additional_properties = None;
|
schema.additional_properties = None;
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
VariantInfo::Struct(struct_variant_info) => FieldsInformation {
|
SchemaEnumType::Fields(fields_information) => fields_information,
|
||||||
fields: get_fields_information(struct_variant_info.iter()),
|
|
||||||
fields_type: FieldType::Named,
|
|
||||||
},
|
|
||||||
VariantInfo::Tuple(tuple_variant_info) => FieldsInformation {
|
|
||||||
fields: get_fields_information(tuple_variant_info.iter()),
|
|
||||||
fields_type: FieldType::Unnamed,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
let mut subschema = JsonSchemaBevyType::default();
|
let mut subschema = JsonSchemaBevyType::default();
|
||||||
registry.update_schema_with_fields_info(&mut subschema, &fields_info);
|
registry.update_schema_with_fields_info(&mut subschema, fields_info);
|
||||||
schema.properties = [(variant.name().into(), subschema.into())].into();
|
schema.properties = [(name.into(), subschema.into())].into();
|
||||||
schema
|
schema
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1444,7 +1476,7 @@ impl TypeDefinitionBuilder for TypeRegistry {
|
|||||||
InternalSchemaType::Optional { generic } => {
|
InternalSchemaType::Optional { generic } => {
|
||||||
id = None;
|
id = None;
|
||||||
let optional_schema = self
|
let optional_schema = self
|
||||||
.build_schema_reference_for_type_id(generic.type_id(), None)
|
.build_schema_reference_for_type_id(generic, None)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
schema.ref_type = None;
|
schema.ref_type = None;
|
||||||
@ -1529,16 +1561,10 @@ impl TypeDefinitionBuilder for TypeRegistry {
|
|||||||
});
|
});
|
||||||
schema.kind = Some(data.schema_kind);
|
schema.kind = Some(data.schema_kind);
|
||||||
}
|
}
|
||||||
if let Some(field_range) = field_data
|
if let Some(field_range) = field_data.as_ref().and_then(|d| d.range) {
|
||||||
.as_ref()
|
|
||||||
.and_then(|d| d.attributes.get_range_by_id(type_id))
|
|
||||||
{
|
|
||||||
range = range.with(field_range);
|
range = range.with(field_range);
|
||||||
}
|
}
|
||||||
if let Some(field_range) = p_field_data
|
if let Some(field_range) = p_field_data.as_ref().and_then(|d| d.range) {
|
||||||
.as_ref()
|
|
||||||
.and_then(|d| d.attributes.get_range_by_id(type_id))
|
|
||||||
{
|
|
||||||
range = range.with(field_range);
|
range = range.with(field_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1584,7 +1610,7 @@ impl TypeDefinitionBuilder for TypeRegistry {
|
|||||||
}
|
}
|
||||||
InternalSchemaType::Optional { generic } => {
|
InternalSchemaType::Optional { generic } => {
|
||||||
let schema_optional = self
|
let schema_optional = self
|
||||||
.build_schema_reference_for_type_id(generic.ty().id(), None)
|
.build_schema_reference_for_type_id(generic, None)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
schema.ref_type = None;
|
schema.ref_type = None;
|
||||||
schema.one_of = vec![
|
schema.one_of = vec![
|
||||||
@ -1749,10 +1775,12 @@ pub(super) mod tests {
|
|||||||
}
|
}
|
||||||
let atr = AppTypeRegistry::default();
|
let atr = AppTypeRegistry::default();
|
||||||
{
|
{
|
||||||
|
use crate::schemas::RegisterReflectJsonSchemas;
|
||||||
|
|
||||||
let mut register = atr.write();
|
let mut register = atr.write();
|
||||||
register.register::<bevy_math::Vec3>();
|
register.register::<bevy_math::Vec3>();
|
||||||
register.register::<Foo>();
|
register.register::<Foo>();
|
||||||
register.register_type_data::<bevy_math::Vec3, ReflectJsonSchemaForceAsArray>();
|
register.register_force_as_array::<bevy_math::Vec3>();
|
||||||
}
|
}
|
||||||
let type_registry = atr.read();
|
let type_registry = atr.read();
|
||||||
let (_, schema) = type_registry
|
let (_, schema) = type_registry
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user