Remove ReflectJsonSchema, functionality is provided by CustomInternalSchemaData

This commit is contained in:
Piotr Siuszko 2025-07-10 19:23:10 +02:00
parent f404446756
commit dd20a3bd34
5 changed files with 124 additions and 121 deletions

View File

@ -1871,7 +1871,7 @@ mod tests {
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_force_as_array::<bevy_math::Vec3>(); register.registry_force_schema_to_be_array::<bevy_math::Vec3>();
} }
let mut world = World::new(); let mut world = World::new();
world.insert_resource(atr); world.insert_resource(atr);

View File

@ -449,7 +449,8 @@ impl SchemaType {
mod tests { mod tests {
use crate::schemas::open_rpc::OpenRpcDocument; use crate::schemas::open_rpc::OpenRpcDocument;
use crate::schemas::reflect_info::ReferenceLocation; use crate::schemas::reflect_info::ReferenceLocation;
use crate::schemas::ReflectJsonSchema; use crate::schemas::CustomInternalSchemaData;
use crate::schemas::ExternalSchemaSource;
use super::*; use super::*;
use bevy_ecs::prelude::ReflectComponent; use bevy_ecs::prelude::ReflectComponent;
@ -631,7 +632,7 @@ mod tests {
{ {
let mut register = atr.write(); let mut register = atr.write();
register.register::<OpenRpcDocument>(); register.register::<OpenRpcDocument>();
register.register_type_data::<OpenRpcDocument, ReflectJsonSchema>(); register.register_type_data::<OpenRpcDocument, CustomInternalSchemaData>();
} }
let type_registry = atr.read(); let type_registry = atr.read();
let schema = type_registry let schema = type_registry
@ -656,20 +657,16 @@ mod tests {
#[test] #[test]
fn reflect_export_with_custom_schema() { fn reflect_export_with_custom_schema() {
/// Custom type for testing purposes.
#[derive(Reflect, Component)] #[derive(Reflect, Component)]
struct SomeType; struct SomeType;
impl bevy_reflect::FromType<SomeType> for ReflectJsonSchema { impl ExternalSchemaSource for SomeType {
fn from_type() -> Self { fn get_external_schema_source() -> TypeReferencePath {
JsonSchemaBevyType { TypeReferencePath::new_ref(
ref_type: Some(TypeReferencePath::new_ref( ReferenceLocation::Url,
ReferenceLocation::Url, "raw.githubusercontent.com/open-rpc/meta-schema/master/schema.json",
"raw.githubusercontent.com/open-rpc/meta-schema/master/schema.json", )
)),
description: Some("Custom type for testing purposes.".into()),
..Default::default()
}
.into()
} }
} }
@ -677,7 +674,7 @@ mod tests {
{ {
let mut register = atr.write(); let mut register = atr.write();
register.register::<SomeType>(); register.register::<SomeType>();
register.register_type_data::<SomeType, ReflectJsonSchema>(); register.register_type_data::<SomeType, CustomInternalSchemaData>();
} }
let type_registry = atr.read(); let type_registry = atr.read();
let schema = type_registry let schema = type_registry

View File

@ -1,6 +1,5 @@
//! Module with schemas used for various BRP endpoints //! Module with schemas used for various BRP endpoints
use alloc::borrow::Cow; use alloc::borrow::Cow;
use bevy_derive::Deref;
use bevy_ecs::{ use bevy_ecs::{
reflect::{ReflectComponent, ReflectResource}, reflect::{ReflectComponent, ReflectResource},
resource::Resource, resource::Resource,
@ -13,9 +12,8 @@ use bevy_reflect::{
use core::any::TypeId; use core::any::TypeId;
use crate::schemas::{ use crate::schemas::{
json_schema::JsonSchemaBevyType,
open_rpc::OpenRpcDocument, open_rpc::OpenRpcDocument,
reflect_info::{FieldsInformation, InternalSchemaType}, reflect_info::{FieldsInformation, InternalSchemaType, TypeReferencePath},
}; };
pub mod json_schema; pub mod json_schema;
@ -36,18 +34,17 @@ pub struct SchemaTypesMetadata {
#[reflect(Resource)] #[reflect(Resource)]
pub struct CustomInternalSchemaData(pub InternalSchemaType); pub struct CustomInternalSchemaData(pub InternalSchemaType);
impl CustomInternalSchemaData { /// Trait for external schema sources.
/// Creates a new `CustomInternalSchema` with a forced array type. Works for structs only. pub trait ExternalSchemaSource {
pub fn force_array<T: GetTypeRegistration>() -> Option<Self> { /// Get the external schema source.
match T::get_type_registration().type_info() { fn get_external_schema_source() -> TypeReferencePath;
bevy_reflect::TypeInfo::Struct(struct_info) => Some(CustomInternalSchemaData( }
InternalSchemaType::FieldsHolder(FieldsInformation::new(
struct_info.iter(), impl<T: Reflect + ExternalSchemaSource> FromType<T> for CustomInternalSchemaData {
reflect_info::FieldType::ForceUnnamed(struct_info.ty().id()), fn from_type() -> Self {
)), Self(InternalSchemaType::ExternalSource(
)), T::get_external_schema_source(),
_ => None, ))
}
} }
} }
@ -57,60 +54,60 @@ 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_force_as_array::<bevy_math::Vec2>(); self.registry_force_schema_to_be_array::<bevy_math::Vec2>();
self.register_force_as_array::<bevy_math::DVec2>(); self.registry_force_schema_to_be_array::<bevy_math::DVec2>();
self.register_force_as_array::<bevy_math::I8Vec2>(); self.registry_force_schema_to_be_array::<bevy_math::I8Vec2>();
self.register_force_as_array::<bevy_math::U8Vec2>(); self.registry_force_schema_to_be_array::<bevy_math::U8Vec2>();
self.register_force_as_array::<bevy_math::I16Vec2>(); self.registry_force_schema_to_be_array::<bevy_math::I16Vec2>();
self.register_force_as_array::<bevy_math::U16Vec2>(); self.registry_force_schema_to_be_array::<bevy_math::U16Vec2>();
self.register_force_as_array::<bevy_math::IVec2>(); self.registry_force_schema_to_be_array::<bevy_math::IVec2>();
self.register_force_as_array::<bevy_math::UVec2>(); self.registry_force_schema_to_be_array::<bevy_math::UVec2>();
self.register_force_as_array::<bevy_math::I64Vec2>(); self.registry_force_schema_to_be_array::<bevy_math::I64Vec2>();
self.register_force_as_array::<bevy_math::U64Vec2>(); self.registry_force_schema_to_be_array::<bevy_math::U64Vec2>();
self.register_force_as_array::<bevy_math::BVec2>(); self.registry_force_schema_to_be_array::<bevy_math::BVec2>();
self.register_force_as_array::<bevy_math::Vec3A>(); self.registry_force_schema_to_be_array::<bevy_math::Vec3A>();
self.register_force_as_array::<bevy_math::Vec3>(); self.registry_force_schema_to_be_array::<bevy_math::Vec3>();
self.register_force_as_array::<bevy_math::DVec3>(); self.registry_force_schema_to_be_array::<bevy_math::DVec3>();
self.register_force_as_array::<bevy_math::I8Vec3>(); self.registry_force_schema_to_be_array::<bevy_math::I8Vec3>();
self.register_force_as_array::<bevy_math::U8Vec3>(); self.registry_force_schema_to_be_array::<bevy_math::U8Vec3>();
self.register_force_as_array::<bevy_math::I16Vec3>(); self.registry_force_schema_to_be_array::<bevy_math::I16Vec3>();
self.register_force_as_array::<bevy_math::U16Vec3>(); self.registry_force_schema_to_be_array::<bevy_math::U16Vec3>();
self.register_force_as_array::<bevy_math::IVec3>(); self.registry_force_schema_to_be_array::<bevy_math::IVec3>();
self.register_force_as_array::<bevy_math::UVec3>(); self.registry_force_schema_to_be_array::<bevy_math::UVec3>();
self.register_force_as_array::<bevy_math::I64Vec3>(); self.registry_force_schema_to_be_array::<bevy_math::I64Vec3>();
self.register_force_as_array::<bevy_math::U64Vec3>(); self.registry_force_schema_to_be_array::<bevy_math::U64Vec3>();
self.register_force_as_array::<bevy_math::BVec3>(); self.registry_force_schema_to_be_array::<bevy_math::BVec3>();
self.register_force_as_array::<bevy_math::Vec4>(); self.registry_force_schema_to_be_array::<bevy_math::Vec4>();
self.register_force_as_array::<bevy_math::DVec4>(); self.registry_force_schema_to_be_array::<bevy_math::DVec4>();
self.register_force_as_array::<bevy_math::I8Vec4>(); self.registry_force_schema_to_be_array::<bevy_math::I8Vec4>();
self.register_force_as_array::<bevy_math::U8Vec4>(); self.registry_force_schema_to_be_array::<bevy_math::U8Vec4>();
self.register_force_as_array::<bevy_math::I16Vec4>(); self.registry_force_schema_to_be_array::<bevy_math::I16Vec4>();
self.register_force_as_array::<bevy_math::U16Vec4>(); self.registry_force_schema_to_be_array::<bevy_math::U16Vec4>();
self.register_force_as_array::<bevy_math::IVec4>(); self.registry_force_schema_to_be_array::<bevy_math::IVec4>();
self.register_force_as_array::<bevy_math::UVec4>(); self.registry_force_schema_to_be_array::<bevy_math::UVec4>();
self.register_force_as_array::<bevy_math::I64Vec4>(); self.registry_force_schema_to_be_array::<bevy_math::I64Vec4>();
self.register_force_as_array::<bevy_math::U64Vec4>(); self.registry_force_schema_to_be_array::<bevy_math::U64Vec4>();
self.register_force_as_array::<bevy_math::BVec4>(); self.registry_force_schema_to_be_array::<bevy_math::BVec4>();
self.register_force_as_array::<bevy_math::Quat>(); self.registry_force_schema_to_be_array::<bevy_math::Quat>();
self.register_force_as_array::<bevy_math::DQuat>(); self.registry_force_schema_to_be_array::<bevy_math::DQuat>();
self.register_force_as_array::<bevy_math::Mat2>(); self.registry_force_schema_to_be_array::<bevy_math::Mat2>();
self.register_force_as_array::<bevy_math::DMat2>(); self.registry_force_schema_to_be_array::<bevy_math::DMat2>();
self.register_force_as_array::<bevy_math::DMat3>(); self.registry_force_schema_to_be_array::<bevy_math::DMat3>();
self.register_force_as_array::<bevy_math::Mat3A>(); self.registry_force_schema_to_be_array::<bevy_math::Mat3A>();
self.register_force_as_array::<bevy_math::Mat3>(); self.registry_force_schema_to_be_array::<bevy_math::Mat3>();
self.register_force_as_array::<bevy_math::DMat4>(); self.registry_force_schema_to_be_array::<bevy_math::DMat4>();
self.register_force_as_array::<bevy_math::Mat4>(); self.registry_force_schema_to_be_array::<bevy_math::Mat4>();
self.register_force_as_array::<bevy_math::Affine2>(); self.registry_force_schema_to_be_array::<bevy_math::Affine2>();
self.register_force_as_array::<bevy_math::DAffine2>(); self.registry_force_schema_to_be_array::<bevy_math::DAffine2>();
self.register_force_as_array::<bevy_math::DAffine3>(); self.registry_force_schema_to_be_array::<bevy_math::DAffine3>();
self.register_force_as_array::<bevy_math::Affine3A>(); self.registry_force_schema_to_be_array::<bevy_math::Affine3A>();
} }
self.register_type_internal::<OpenRpcDocument>(); self.register_type_internal::<OpenRpcDocument>();
self.register_type_data_internal::<OpenRpcDocument, ReflectJsonSchema>(); self.register_type_data_internal::<OpenRpcDocument, CustomInternalSchemaData>();
} }
/// Registers a type by value. /// Registers a type by value.
fn register_data_type_by_value<T, D>(&mut self, data: D) fn register_data_type_by_value<T, D>(&mut self, data: D)
@ -125,13 +122,21 @@ pub(crate) trait RegisterReflectJsonSchemas {
where where
T: Reflect + TypePath + GetTypeRegistration, T: Reflect + TypePath + GetTypeRegistration,
D: TypeData + FromType<T>; D: TypeData + FromType<T>;
fn register_force_as_array<T>(&mut self) /// Registers a [`CustomInternalSchemaData`] data type for a type that will force to treat the type as an array during building the [`JsonSchemaBevyType`] for given type.
/// It is useful when you want to force the type to be treated as an array in the schema, for example when type has custom serialization.
fn registry_force_schema_to_be_array<T>(&mut self)
where where
T: Reflect + TypePath + GetTypeRegistration, T: Reflect + TypePath + GetTypeRegistration,
{ {
let Some(data) = CustomInternalSchemaData::force_array::<T>() else { let bevy_reflect::TypeInfo::Struct(struct_info) = T::get_type_registration().type_info()
else {
return; return;
}; };
let data =
CustomInternalSchemaData(InternalSchemaType::FieldsHolder(FieldsInformation::new(
struct_info.iter(),
reflect_info::FieldType::ForceUnnamed(struct_info.ty().id()),
)));
self.register_data_type_by_value::<T, CustomInternalSchemaData>(data); self.register_data_type_by_value::<T, CustomInternalSchemaData>(data);
} }
} }
@ -195,22 +200,6 @@ impl RegisterReflectJsonSchemas for bevy_app::App {
} }
} }
/// Reflect-compatible custom JSON Schema for this type
#[derive(Clone, Deref)]
pub struct ReflectJsonSchema(pub JsonSchemaBevyType);
impl From<&JsonSchemaBevyType> for ReflectJsonSchema {
fn from(schema: &JsonSchemaBevyType) -> Self {
Self(schema.clone())
}
}
impl From<JsonSchemaBevyType> for ReflectJsonSchema {
fn from(schema: JsonSchemaBevyType) -> Self {
Self(schema)
}
}
impl Default for SchemaTypesMetadata { impl Default for SchemaTypesMetadata {
fn default() -> Self { fn default() -> Self {
let mut data_types = Self { let mut data_types = Self {

View File

@ -1,15 +1,12 @@
//! Module with trimmed down `OpenRPC` document structs. //! Module with trimmed down `OpenRPC` document structs.
//! It tries to follow this standard: <https://spec.open-rpc.org> //! It tries to follow this standard: <https://spec.open-rpc.org>
use bevy_platform::collections::HashMap; use bevy_platform::collections::HashMap;
use bevy_reflect::{FromType, Reflect}; use bevy_reflect::Reflect;
use bevy_utils::default; use bevy_utils::default;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
schemas::{ schemas::reflect_info::{ReferenceLocation, TypeReferencePath},
reflect_info::{ReferenceLocation, TypeReferencePath},
ReflectJsonSchema,
},
RemoteMethods, RemoteMethods,
}; };
@ -29,20 +26,12 @@ pub struct OpenRpcDocument {
pub servers: Option<Vec<ServerObject>>, pub servers: Option<Vec<ServerObject>>,
} }
impl FromType<OpenRpcDocument> for ReflectJsonSchema { impl super::ExternalSchemaSource for OpenRpcDocument {
fn from_type() -> Self { fn get_external_schema_source() -> TypeReferencePath {
JsonSchemaBevyType { TypeReferencePath::new_ref(
ref_type: Some(TypeReferencePath::new_ref( ReferenceLocation::Url,
ReferenceLocation::Url, "raw.githubusercontent.com/open-rpc/meta-schema/master/schema.json",
"raw.githubusercontent.com/open-rpc/meta-schema/master/schema.json", )
)),
description: Some(
"Represents an `OpenRPC` document as defined by the `OpenRPC` specification."
.into(),
),
..default()
}
.into()
} }
} }

View File

@ -531,7 +531,16 @@ impl TypeReferencePath {
} }
impl Display for TypeReferencePath { impl Display for TypeReferencePath {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}{}", self.location, encode_to_uri(&self.id)) write!(
f,
"{}{}",
self.location,
if self.location == ReferenceLocation::Definitions {
encode_to_uri(&self.id)
} else {
(*self.id).to_string()
}
)
} }
} }
@ -929,6 +938,8 @@ pub enum InternalSchemaType {
/// Optional field data for the primitive type. /// Optional field data for the primitive type.
field_data: Option<SchemaFieldData>, field_data: Option<SchemaFieldData>,
}, },
/// Variant for external source types.
ExternalSource(TypeReferencePath),
/// Variant for regular primitive types and other simple types. /// Variant for regular primitive types and other simple types.
Regular(TypeId), Regular(TypeId),
} }
@ -1100,7 +1111,7 @@ impl InternalSchemaType {
InternalSchemaType::Regular(t) => { InternalSchemaType::Regular(t) => {
_ = dependencies.insert(*t); _ = dependencies.insert(*t);
} }
InternalSchemaType::PrimitiveType { .. } => {} InternalSchemaType::PrimitiveType { .. } | InternalSchemaType::ExternalSource(_) => {}
} }
dependencies dependencies
} }
@ -1137,7 +1148,9 @@ impl From<&InternalSchemaType> for Option<SchemaTypeVariant> {
InternalSchemaType::Regular(type_id) => { InternalSchemaType::Regular(type_id) => {
Some(SchemaTypeVariant::Single((*type_id).into())) Some(SchemaTypeVariant::Single((*type_id).into()))
} }
InternalSchemaType::EnumHolder(_) | InternalSchemaType::Optional { generic: _ } => None, InternalSchemaType::EnumHolder(_)
| InternalSchemaType::Optional { generic: _ }
| InternalSchemaType::ExternalSource(_) => None,
} }
} }
} }
@ -1472,9 +1485,7 @@ impl TypeDefinitionBuilder for TypeRegistry {
let internal = InternalSchemaType::from_type_registration(type_reg, self); let internal = InternalSchemaType::from_type_registration(type_reg, self);
let mut id: Option<TypeReferenceId> = Some(type_reg.type_info().type_path().into()); let mut id: Option<TypeReferenceId> = Some(type_reg.type_info().type_path().into());
if let Some(custom_schema) = &type_reg.data::<super::ReflectJsonSchema>() {
return Some((id, custom_schema.0.clone()));
}
let range: MinMaxValues = type_id.into(); let range: MinMaxValues = type_id.into();
let type_path_table = type_reg.type_info().type_path_table(); let type_path_table = type_reg.type_info().type_path_table();
let (type_path, short_path, crate_name, module_path) = ( let (type_path, short_path, crate_name, module_path) = (
@ -1512,6 +1523,16 @@ impl TypeDefinitionBuilder for TypeRegistry {
}; };
schema.schema_type = (&internal).into(); schema.schema_type = (&internal).into();
match internal { match internal {
InternalSchemaType::ExternalSource(source) => {
return Some((
None,
JsonSchemaBevyType {
description: schema.description,
ref_type: Some(source),
..Default::default()
},
));
}
InternalSchemaType::PrimitiveType { InternalSchemaType::PrimitiveType {
type_id: _, type_id: _,
primitive: _, primitive: _,
@ -1641,6 +1662,13 @@ impl TypeDefinitionBuilder for TypeRegistry {
let internal = InternalSchemaType::from_type_registration(type_reg, self); let internal = InternalSchemaType::from_type_registration(type_reg, self);
schema.schema_type = (&internal).into(); schema.schema_type = (&internal).into();
match internal { match internal {
InternalSchemaType::ExternalSource(source) => {
return Some(JsonSchemaBevyType {
description: schema.description,
ref_type: Some(source),
..Default::default()
});
}
InternalSchemaType::PrimitiveType { InternalSchemaType::PrimitiveType {
type_id, type_id,
primitive: _, primitive: _,