use serde::Serialize;
use serde_json::Map;
use serde_json::Value;
use strum::AsRefStr;
use strum::Display;
use strum::EnumString;
use crate::brp_tools::BrpTypeName;
use crate::constants::SCHEMA_REF_PREFIX;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, AsRefStr, Serialize, EnumString)]
#[strum(serialize_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub(crate) enum JsonSchemaType {
Object,
Array,
String,
Number,
Integer,
Boolean,
Null,
}
impl From<JsonSchemaType> for Value {
fn from(schema_type: JsonSchemaType) -> Self { Self::String(schema_type.as_ref().to_string()) }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, AsRefStr)]
#[strum(serialize_all = "camelCase")]
pub(crate) enum SchemaField {
AdditionalProperties,
#[strum(serialize = "anyOf")]
AnyOf,
Const,
ComponentInfo,
CrateName,
#[strum(serialize = "$defs")]
Defs,
Description,
Items,
Key,
KeyType,
Kind,
ModulePath,
OneOf,
PrefixItems,
Properties,
#[strum(serialize = "$ref")]
Ref,
ReflectTypes,
Required,
ShortPath,
Type,
TypePath,
Value,
ValueType,
}
pub(crate) trait JsonObjectAccess {
fn get_field<T: AsRef<str>>(&self, field: T) -> Option<&Value>;
fn get_field_str<T: AsRef<str>>(&self, field: T) -> Option<&str>;
fn get_field_string<T: AsRef<str>>(&self, field: T) -> Option<String> {
self.get_field_str(field).map(String::from)
}
fn get_field_array<T: AsRef<str>>(&self, field: T) -> Option<&[Value]> {
self.get_field(field)
.and_then(Value::as_array)
.map(Vec::as_slice)
}
fn insert_field<F, V>(&mut self, field: F, value: V)
where
F: Into<String>,
V: Into<Value>;
fn extract_field_type(&self) -> Option<BrpTypeName> {
self.get_field(SchemaField::Type)
.and_then(|field_type| field_type.get_field(SchemaField::Ref))
.and_then(Value::as_str)
.and_then(|ref_str| ref_str.strip_prefix(SCHEMA_REF_PREFIX))
.map(BrpTypeName::from)
}
fn get_type(&self, schema_field: SchemaField) -> Option<BrpTypeName> {
let field_value = self.get_field(schema_field)?;
field_value.extract_field_type()
}
fn get_properties(&self) -> Option<&Map<String, Value>> {
self.get_field(SchemaField::Properties)
.and_then(Value::as_object)
}
fn is_complex_type(&self) -> bool;
}
impl JsonObjectAccess for Value {
fn get_field<T: AsRef<str>>(&self, field: T) -> Option<&Self> { self.get(field.as_ref()) }
fn get_field_str<T: AsRef<str>>(&self, field: T) -> Option<&str> {
self.get(field.as_ref()).and_then(Self::as_str)
}
fn insert_field<F, V>(&mut self, field: F, value: V)
where
F: Into<String>,
V: Into<Self>,
{
if let Some(obj) = self.as_object_mut() {
obj.insert(field.into(), value.into());
}
}
fn is_complex_type(&self) -> bool { matches!(self, Self::Array(_) | Self::Object(_)) }
}
impl JsonObjectAccess for Map<String, Value> {
fn get_field<T: AsRef<str>>(&self, field: T) -> Option<&Value> { self.get(field.as_ref()) }
fn get_field_str<T: AsRef<str>>(&self, field: T) -> Option<&str> {
self.get(field.as_ref()).and_then(Value::as_str)
}
fn insert_field<F, V>(&mut self, field: F, value: V)
where
F: Into<String>,
V: Into<Value>,
{
self.insert(field.into(), value.into());
}
fn is_complex_type(&self) -> bool {
true
}
}
pub(crate) trait IntoStrings<T> {
fn into_strings(self) -> Vec<String>;
}
impl<I, T> IntoStrings<T> for I
where
I: Iterator<Item = T>,
T: Into<String>,
{
fn into_strings(self) -> Vec<String> { self.map(Into::into).collect() }
}