Use Cow instead of String in JSON schema types
This commit is contained in:
parent
16f9c87bdd
commit
e93680baa3
@ -1,6 +1,7 @@
|
||||
//! Built-in verbs for the Bevy Remote Protocol.
|
||||
|
||||
use core::any::TypeId;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use anyhow::{anyhow, Result as AnyhowResult};
|
||||
use bevy_ecs::{
|
||||
@ -1268,7 +1269,7 @@ pub fn export_registry_types(In(params): In<Option<Value>>, world: &World) -> Br
|
||||
}
|
||||
Some((type_reg.type_info().type_path().into(), schema))
|
||||
})
|
||||
.collect::<HashMap<String, JsonSchemaBevyType>>();
|
||||
.collect::<HashMap<Cow<'static, str>, JsonSchemaBevyType>>();
|
||||
|
||||
serde_json::to_value(schemas).map_err(BrpError::internal)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use bevy_reflect::{
|
||||
use core::any::TypeId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::schemas::{
|
||||
reflect_info::{SchemaInfoReflect, SchemaNumber},
|
||||
@ -102,11 +103,11 @@ impl TryFrom<&TypeRegistration> for JsonSchemaBevyType {
|
||||
|
||||
/// Identifies the JSON Schema version used in the schema.
|
||||
#[derive(Deserialize, Serialize, Debug, Reflect, PartialEq, Clone)]
|
||||
pub struct SchemaMarker(String);
|
||||
pub struct SchemaMarker(Cow<'static, str>);
|
||||
|
||||
impl Default for SchemaMarker {
|
||||
fn default() -> Self {
|
||||
Self("https://json-schema.org/draft/2020-12/schema".to_string())
|
||||
Self("https://json-schema.org/draft/2020-12/schema".into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,22 +126,22 @@ pub struct JsonSchemaBevyType {
|
||||
/// This keyword is used to reference a statically identified schema.
|
||||
#[serde(rename = "$ref")]
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub ref_type: Option<String>,
|
||||
pub ref_type: Option<Cow<'static, str>>,
|
||||
/// Bevy specific field, short path of the type.
|
||||
#[serde(skip_serializing_if = "String::is_empty", default)]
|
||||
pub short_path: String,
|
||||
#[serde(skip_serializing_if = "str::is_empty", default)]
|
||||
pub short_path: Cow<'static, str>,
|
||||
/// Bevy specific field, full path of the type.
|
||||
#[serde(skip_serializing_if = "String::is_empty", default)]
|
||||
pub type_path: String,
|
||||
#[serde(skip_serializing_if = "str::is_empty", default)]
|
||||
pub type_path: Cow<'static, str>,
|
||||
/// Bevy specific field, path of the module that type is part of.
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub module_path: Option<String>,
|
||||
pub module_path: Option<Cow<'static, str>>,
|
||||
/// Bevy specific field, name of the crate that type is part of.
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub crate_name: Option<String>,
|
||||
pub crate_name: Option<Cow<'static, str>>,
|
||||
/// Bevy specific field, names of the types that type reflects.
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub reflect_types: Vec<String>,
|
||||
pub reflect_types: Vec<Cow<'static, str>>,
|
||||
/// Bevy specific field, [`TypeInfo`] type mapping.
|
||||
pub kind: SchemaKind,
|
||||
/// Bevy specific field, provided when [`SchemaKind`] `kind` field is equal to [`SchemaKind::Map`].
|
||||
@ -167,10 +168,10 @@ pub struct JsonSchemaBevyType {
|
||||
/// within this keyword's value, the child instance for that name successfully validates
|
||||
/// against the corresponding schema.
|
||||
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
|
||||
pub properties: HashMap<String, JsonSchemaVariant>,
|
||||
pub properties: HashMap<Cow<'static, str>, JsonSchemaVariant>,
|
||||
/// An object instance is valid against this keyword if every item in the array is the name of a property in the instance.
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub required: Vec<String>,
|
||||
pub required: Vec<Cow<'static, str>>,
|
||||
/// An instance validates successfully against this keyword if it validates successfully against exactly one schema defined by this keyword's value.
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub one_of: Vec<JsonSchemaVariant>,
|
||||
@ -452,19 +453,24 @@ mod tests {
|
||||
let schema = export_type::<Foo>();
|
||||
|
||||
assert!(
|
||||
!schema.reflect_types.contains(&"Component".to_owned()),
|
||||
!schema.reflect_types.contains(&Cow::Borrowed("Component")),
|
||||
"Should not be a component"
|
||||
);
|
||||
assert!(
|
||||
schema.reflect_types.contains(&"Resource".to_owned()),
|
||||
schema.reflect_types.contains(&Cow::Borrowed("Resource")),
|
||||
"Should be a resource"
|
||||
);
|
||||
|
||||
let _ = schema.properties.get("a").expect("Missing `a` field");
|
||||
let _ = schema.properties.get("b").expect("Missing `b` field");
|
||||
assert!(
|
||||
schema.required.contains(&"a".to_owned()),
|
||||
schema.required.contains(&Cow::Borrowed("a")),
|
||||
"Field a should be required"
|
||||
);
|
||||
assert!(
|
||||
schema.required.contains(&Cow::Borrowed("b")),
|
||||
"Field b should be required"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -482,11 +488,11 @@ mod tests {
|
||||
}
|
||||
let schema = export_type::<EnumComponent>();
|
||||
assert!(
|
||||
schema.reflect_types.contains(&"Component".to_owned()),
|
||||
schema.reflect_types.contains(&Cow::Borrowed("Component")),
|
||||
"Should be a component"
|
||||
);
|
||||
assert!(
|
||||
!schema.reflect_types.contains(&"Resource".to_owned()),
|
||||
!schema.reflect_types.contains(&Cow::Borrowed("Resource")),
|
||||
"Should not be a resource"
|
||||
);
|
||||
assert!(schema.properties.is_empty(), "Should not have any field");
|
||||
@ -506,11 +512,11 @@ mod tests {
|
||||
}
|
||||
let schema = export_type::<EnumComponent>();
|
||||
assert!(
|
||||
!schema.reflect_types.contains(&"Component".to_owned()),
|
||||
!schema.reflect_types.contains(&Cow::Borrowed("Component")),
|
||||
"Should not be a component"
|
||||
);
|
||||
assert!(
|
||||
!schema.reflect_types.contains(&"Resource".to_owned()),
|
||||
!schema.reflect_types.contains(&Cow::Borrowed("Resource")),
|
||||
"Should not be a resource"
|
||||
);
|
||||
assert!(schema.properties.is_empty(), "Should not have any field");
|
||||
@ -601,7 +607,7 @@ mod tests {
|
||||
.export_type_json_schema::<SomeType>(&SchemaTypesMetadata::default())
|
||||
.expect("Failed to export schema");
|
||||
assert!(
|
||||
!schema.reflect_types.contains(&"Component".to_owned()),
|
||||
!schema.reflect_types.contains(&Cow::Borrowed("Component")),
|
||||
"Should not be a component"
|
||||
);
|
||||
assert!(
|
||||
@ -621,11 +627,11 @@ mod tests {
|
||||
|
||||
let schema = export_type::<TupleStructType>();
|
||||
assert!(
|
||||
schema.reflect_types.contains(&"Component".to_owned()),
|
||||
schema.reflect_types.contains(&Cow::Borrowed("Component")),
|
||||
"Should be a component"
|
||||
);
|
||||
assert!(
|
||||
!schema.reflect_types.contains(&"Resource".to_owned()),
|
||||
!schema.reflect_types.contains(&Cow::Borrowed("Resource")),
|
||||
"Should not be a resource"
|
||||
);
|
||||
assert!(schema.properties.is_empty(), "Should not have any field");
|
||||
|
@ -10,6 +10,7 @@ use bevy_reflect::{
|
||||
TypeRegistration,
|
||||
};
|
||||
use core::any::TypeId;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::schemas::json_schema::JsonSchemaBevyType;
|
||||
|
||||
@ -23,7 +24,7 @@ pub mod reflect_info;
|
||||
#[reflect(Resource)]
|
||||
pub struct SchemaTypesMetadata {
|
||||
/// Type Data id mapping to human-readable type names.
|
||||
pub type_data_map: HashMap<TypeId, String>,
|
||||
pub type_data_map: HashMap<TypeId, Cow<'static, str>>,
|
||||
}
|
||||
|
||||
/// Reflect-compatible custom JSON Schema for this type
|
||||
@ -62,12 +63,12 @@ impl Default for SchemaTypesMetadata {
|
||||
|
||||
impl SchemaTypesMetadata {
|
||||
/// Map `TypeId` of `TypeData` to a human-readable type name
|
||||
pub fn map_type_data<T: TypeData>(&mut self, name: impl Into<String>) {
|
||||
pub fn map_type_data<T: TypeData>(&mut self, name: impl Into<Cow<'static, str>>) {
|
||||
self.type_data_map.insert(TypeId::of::<T>(), name.into());
|
||||
}
|
||||
|
||||
/// Build reflect types list for a given type registration
|
||||
pub fn get_registered_reflect_types(&self, reg: &TypeRegistration) -> Vec<String> {
|
||||
pub fn get_registered_reflect_types(&self, reg: &TypeRegistration) -> Vec<Cow<'static, str>> {
|
||||
self.type_data_map
|
||||
.iter()
|
||||
.filter_map(|(id, name)| reg.data_by_id(*id).and(Some(name.clone())))
|
||||
@ -75,12 +76,16 @@ impl SchemaTypesMetadata {
|
||||
}
|
||||
|
||||
/// Checks if slice contains a type name that matches the checked `TypeData`
|
||||
pub fn has_type_data<T: TypeData>(&self, types_string_slice: &[String]) -> bool {
|
||||
pub fn has_type_data<T: TypeData>(&self, types_string_slice: &[Cow<'static, str>]) -> bool {
|
||||
self.has_type_data_by_id(TypeId::of::<T>(), types_string_slice)
|
||||
}
|
||||
|
||||
/// Checks if slice contains a type name that matches the checked `TypeData` by id.
|
||||
pub fn has_type_data_by_id(&self, id: TypeId, types_string_slice: &[String]) -> bool {
|
||||
pub fn has_type_data_by_id(
|
||||
&self,
|
||||
id: TypeId,
|
||||
types_string_slice: &[Cow<'static, str>],
|
||||
) -> bool {
|
||||
self.type_data_map
|
||||
.get(&id)
|
||||
.is_some_and(|data_s| types_string_slice.iter().any(|e| e.eq(data_s)))
|
||||
|
@ -334,21 +334,21 @@ impl Into<JsonSchemaVariant> for SchemaTypeInfo {
|
||||
type_path: self
|
||||
.type_info
|
||||
.as_ref()
|
||||
.and_then(|s| Some(s.type_path_table().path().to_owned()))
|
||||
.and_then(|s| Some(s.type_path_table().path().into()))
|
||||
.unwrap_or_default(),
|
||||
short_path: self
|
||||
.type_info
|
||||
.as_ref()
|
||||
.and_then(|s| Some(s.type_path_table().short_path().to_owned()))
|
||||
.and_then(|s| Some(s.type_path_table().short_path().into()))
|
||||
.unwrap_or_default(),
|
||||
crate_name: self
|
||||
.type_info
|
||||
.as_ref()
|
||||
.and_then(|s| s.type_path_table().crate_name().map(str::to_owned)),
|
||||
.and_then(|s| s.type_path_table().crate_name().map(Into::into)),
|
||||
module_path: self
|
||||
.type_info
|
||||
.as_ref()
|
||||
.and_then(|s| s.type_path_table().module_path().map(str::to_owned)),
|
||||
.and_then(|s| s.type_path_table().module_path().map(Into::into)),
|
||||
minimum: self.range.min.as_ref().and_then(|r| r.get_inclusive()),
|
||||
maximum: self.range.max.as_ref().and_then(|r| r.get_inclusive()),
|
||||
exclusive_minimum: self.range.min.as_ref().and_then(|r| r.get_exclusive()),
|
||||
@ -396,9 +396,8 @@ impl Into<JsonSchemaVariant> for SchemaTypeInfo {
|
||||
range: MinMaxValues::default(),
|
||||
};
|
||||
|
||||
schema.properties =
|
||||
[(variant_info.name().to_string(), schema_field.into())].into();
|
||||
schema.required = vec![variant_info.name().to_string()];
|
||||
schema.properties = [(variant_info.name().into(), schema_field.into())].into();
|
||||
schema.required = vec![variant_info.name().into()];
|
||||
}
|
||||
VariantInfo::Tuple(tuple_variant_info) => {
|
||||
schema.kind = SchemaKind::Value;
|
||||
@ -414,9 +413,8 @@ impl Into<JsonSchemaVariant> for SchemaTypeInfo {
|
||||
type_id: Some(tuple_variant_info.type_id()),
|
||||
range: MinMaxValues::default(),
|
||||
};
|
||||
schema.properties =
|
||||
[(variant_info.name().to_string(), schema_field.into())].into();
|
||||
schema.required = vec![variant_info.name().to_string()];
|
||||
schema.properties = [(variant_info.name().into(), schema_field.into())].into();
|
||||
schema.required = vec![variant_info.name().into()];
|
||||
}
|
||||
VariantInfo::Unit(unit_variant_info) => {
|
||||
return JsonSchemaVariant::const_value(
|
||||
@ -430,11 +428,11 @@ impl Into<JsonSchemaVariant> for SchemaTypeInfo {
|
||||
schema.schema_type = Some(SchemaTypeVariant::Single(SchemaType::Object));
|
||||
schema.properties = named_fields
|
||||
.iter()
|
||||
.map(|field| (field.name().to_string(), field.build_schema()))
|
||||
.map(|field| (field.name().into(), field.build_schema()))
|
||||
.collect();
|
||||
schema.required = named_fields
|
||||
.iter()
|
||||
.map(|field| field.name().to_string())
|
||||
.map(|field| field.name().into())
|
||||
.collect();
|
||||
}
|
||||
InternalSchemaType::UnnamedFieldsHolder(unnamed_fields) => {
|
||||
|
Loading…
Reference in New Issue
Block a user