use serde::{Deserialize, Serialize};
use crate::{OpenAPI, Parameter, Response, Schema};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(untagged)]
pub enum ReferenceOr<T> {
Reference {
#[serde(rename = "$ref")]
reference: String,
},
Item(T),
}
impl<T> ReferenceOr<T> {
pub fn ref_(r: &str) -> Self {
ReferenceOr::Reference {
reference: r.to_owned(),
}
}
pub fn boxed_item(item: T) -> ReferenceOr<Box<T>> {
ReferenceOr::Item(Box::new(item))
}
pub fn into_item(self) -> Option<T> {
match self {
ReferenceOr::Reference { .. } => None,
ReferenceOr::Item(i) => Some(i),
}
}
pub fn as_item(&self) -> Option<&T> {
match self {
ReferenceOr::Reference { .. } => None,
ReferenceOr::Item(i) => Some(i),
}
}
pub fn as_mut(&mut self) -> Option<&mut T> {
match self {
ReferenceOr::Reference { .. } => None,
ReferenceOr::Item(i) => Some(i),
}
}
}
impl<T: 'static> ReferenceOr<T> {
pub fn as_ref(&self) -> ReferenceOr<&T> {
match self {
ReferenceOr::Reference { reference } => ReferenceOr::Reference { reference: reference.clone() },
ReferenceOr::Item(i) => ReferenceOr::Item(i),
}
}
}
pub fn get_component_name(reference: &str) -> Option<&str> {
let mut parts = reference.split('/');
if parts.next() != Some("#") {
return None;
}
if parts.next() != Some("components") {
return None;
}
if parts.next() != Some("schemas") {
return None;
}
parts.next()
}
impl ReferenceOr<Schema> {
pub fn resolve<'a>(&'a self, spec: &'a OpenAPI) -> &'a Schema {
match self {
ReferenceOr::Reference { reference } => {
let name = get_component_name(&reference).unwrap();
let components = spec.components.as_ref().unwrap();
let ref_or_schema = components.schemas.get(name).unwrap();
match ref_or_schema {
ReferenceOr::Item(schema) => schema,
ReferenceOr::Reference { .. } => ref_or_schema.resolve(spec),
}
},
ReferenceOr::Item(schema) => schema,
}
}
}
impl ReferenceOr<Box<Schema>> {
pub fn unbox(&self) -> ReferenceOr<Schema> {
match self {
ReferenceOr::Reference { reference } => ReferenceOr::Reference { reference: reference.clone() },
ReferenceOr::Item(boxed) => ReferenceOr::Item(*boxed.clone()),
}
}
}
pub fn get_parameter_name(reference: &str) -> Option<&str> {
let mut parts = reference.split('/');
if parts.next() != Some("#") {
return None;
}
if parts.next() != Some("components") {
return None;
}
if parts.next() != Some("parameters") {
return None;
}
parts.next()
}
impl ReferenceOr<Parameter> {
pub fn resolve<'a>(&'a self, spec: &'a OpenAPI) -> &'a Parameter {
match self {
ReferenceOr::Reference { reference } => {
let name = get_parameter_name(&reference).unwrap();
let components = spec.components.as_ref().unwrap();
let ref_or_parameter = components.parameters.get(name).unwrap();
match ref_or_parameter {
ReferenceOr::Item(schema) => schema,
ReferenceOr::Reference { .. } => ref_or_parameter.resolve(spec),
}
},
ReferenceOr::Item(parameter) => parameter,
}
}
}
pub fn get_response_name(reference: &str) -> Option<&str> {
let mut parts = reference.split('/');
if parts.next() != Some("#") {
return None;
}
if parts.next() != Some("components") {
return None;
}
if parts.next() != Some("responses") {
return None;
}
parts.next()
}
impl ReferenceOr<Response> {
pub fn resolve<'a>(&'a self, spec: &'a OpenAPI) -> &'a Response {
match self {
ReferenceOr::Reference { reference } => {
let name = get_response_name(&reference).unwrap();
let components = spec.components.as_ref().unwrap();
let ref_or_response = components.responses.get(name).unwrap();
match ref_or_response {
ReferenceOr::Item(schema) => schema,
ReferenceOr::Reference { .. } => ref_or_response.resolve(spec),
}
},
ReferenceOr::Item(response) => response,
}
}
}