openapi-31 0.4.0

OpenAPI v3.1 Specification
Documentation
// OpenAPI v3.1.0 Specification
//
// OpenAPI inside OpenAPI
//
// The version of the OpenAPI document: 3.1.0
//
// Generated by: https://openapi-generator.tech

use std::{default, ops::Deref};

use derive_more::{Display, Error};

use crate::v31;

#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct Reference {
  #[serde(rename = "$ref", skip_serializing_if = "Option::is_none")]
  pub dollar_ref: Option<String>,
  #[serde(rename = "summary", skip_serializing_if = "Option::is_none")]
  pub summary: Option<String>,
  #[serde(rename = "description", skip_serializing_if = "Option::is_none")]
  pub description: Option<String>,
}

impl Reference {
  pub fn new() -> Reference {
    Reference { dollar_ref: None, summary: None, description: None }
  }
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum ObjectOrRef<T> {
  Object(T),
  Ref {
    #[serde(rename = "$ref")]
    r#ref: String,
  },
}

#[derive(Clone, Debug, PartialEq, Display, Error)]
pub enum ObjectRefErr {
  #[display(fmt = "unresolved reference")]
  UnresolvedRef,

  #[display(fmt = "mismatch reference")]
  MismatchedRef,

  #[display(fmt = "reference error")]
  Ref,
}

impl<T> ObjectOrRef<T>
where
  T: Resolve + Clone,
{
  pub fn resolve(&self, openapi: &v31::Openapi) -> Result<T, ObjectRefErr> {
    match self {
      ObjectOrRef::Object(object) => Ok(object.clone()),
      ObjectOrRef::Ref { r#ref } => T::resolve(r#ref, openapi),
    }
  }
}

pub trait Resolve {
  fn resolve(r#ref: &str, openapi: &v31::Openapi) -> Result<Self, ObjectRefErr>
  where
    Self: Sized;
}

#[macro_export]
macro_rules! default_resolve_strategy {
  ($ref:ident, $openapi:ident, $component:ident, $postfix:literal) => {{
    static REF_PREFIX: &str = concat!("#/components/", $postfix, "/");
    if !$ref.starts_with(REF_PREFIX) {
      return Err(v31::reference::ObjectRefErr::MismatchedRef);
    }
    let (_, item_name) = $ref.split_at(REF_PREFIX.len());
    $openapi
      .components
      .as_ref()
      .and_then(|components| components.$component.as_ref())
      .and_then(|items| items.get(item_name))
      .and_then(|item| Some(item.clone()))
      .ok_or_else(|| v31::reference::ObjectRefErr::UnresolvedRef)
  }};
}

impl Resolve for v31::Parameter {
  fn resolve(r#ref: &str, openapi: &v31::Openapi) -> Result<Self, v31::reference::ObjectRefErr> {
    default_resolve_strategy!(r#ref, openapi, parameters, "parameters")
  }
}

impl Resolve for v31::Response {
  fn resolve(r#ref: &str, openapi: &v31::Openapi) -> Result<Self, v31::reference::ObjectRefErr> {
    default_resolve_strategy!(r#ref, openapi, responses, "responses")
  }
}

impl Resolve for v31::Examples {
  fn resolve(r#ref: &str, openapi: &v31::Openapi) -> Result<Self, v31::reference::ObjectRefErr> {
    default_resolve_strategy!(r#ref, openapi, examples, "examples")
  }
}

impl Resolve for v31::RequestBody {
  fn resolve(r#ref: &str, openapi: &v31::Openapi) -> Result<Self, v31::reference::ObjectRefErr> {
    default_resolve_strategy!(r#ref, openapi, request_bodies, "requestBodies")
  }
}

impl Resolve for v31::Header {
  fn resolve(r#ref: &str, openapi: &v31::Openapi) -> Result<Self, v31::reference::ObjectRefErr> {
    default_resolve_strategy!(r#ref, openapi, headers, "headers")
  }
}

impl Resolve for v31::SecurityScheme {
  fn resolve(r#ref: &str, openapi: &v31::Openapi) -> Result<Self, ObjectRefErr> {
    default_resolve_strategy!(r#ref, openapi, security_schemes, "securitySchemas")
  }
}

impl Resolve for v31::Link {
  fn resolve(r#ref: &str, openapi: &v31::Openapi) -> Result<Self, ObjectRefErr> {
    default_resolve_strategy!(r#ref, openapi, links, "links")
  }
}

impl Resolve for v31::PathItem {
  fn resolve(r#ref: &str, openapi: &v31::Openapi) -> Result<Self, v31::reference::ObjectRefErr> {
    default_resolve_strategy!(r#ref, openapi, path_items, "pathItems")
  }
}