use std::{any::type_name, marker::PhantomData};
use crate::{
gen::GenContext,
openapi::{
Components, Contact, Info, License, OpenApi, Operation, Parameter, PathItem, ReferenceOr,
Response, SecurityScheme, Server, StatusCode, Tag,
},
OperationInput,
};
use indexmap::IndexMap;
use serde::Serialize;
use crate::{error::Error, gen::in_context, operation::OperationOutput, util::iter_operations_mut};
#[must_use]
pub struct TransformOpenApi<'t> {
pub(crate) api: &'t mut OpenApi,
}
impl<'t> TransformOpenApi<'t> {
pub fn new(api: &'t mut OpenApi) -> Self {
Self { api }
}
#[tracing::instrument(skip_all)]
pub fn title(self, title: &str) -> Self {
self.api.info.title = title.into();
self
}
#[tracing::instrument(skip_all)]
pub fn summary(self, summary: &str) -> Self {
self.api.info.summary = Some(summary.into());
self
}
#[tracing::instrument(skip_all)]
pub fn tos(self, tos: &str) -> Self {
self.api.info.terms_of_service = Some(tos.into());
self
}
#[tracing::instrument(skip_all)]
pub fn description(self, description: &str) -> Self {
self.api.info.description = Some(description.into());
self
}
#[tracing::instrument(skip_all)]
pub fn version(self, version: &str) -> Self {
self.api.info.version = version.into();
self
}
#[tracing::instrument(skip_all)]
pub fn contact(self, contact: Contact) -> Self {
self.api.info.contact = Some(contact);
self
}
#[tracing::instrument(skip_all)]
pub fn license(self, license: License) -> Self {
self.api.info.license = Some(license);
self
}
#[tracing::instrument(skip_all)]
pub fn info(self, info: Info) -> Self {
self.api.info = info;
self
}
#[tracing::instrument(skip_all)]
pub fn tag(self, tag: Tag) -> Self {
self.api.tags.push(tag);
self
}
#[tracing::instrument(skip_all)]
pub fn server(self, server: Server) -> Self {
self.api.servers.push(server);
self
}
#[tracing::instrument(skip_all)]
pub fn default_response<R>(self) -> Self
where
R: OperationOutput,
{
if let Some(p) = &mut self.api.paths {
for (_, p) in &mut p.paths {
let p = match p {
ReferenceOr::Reference { .. } => continue,
ReferenceOr::Item(p) => p,
};
let _ = TransformPathItem::new(p).default_response::<R>();
}
}
self
}
#[tracing::instrument(skip_all)]
pub fn default_response_with<R, F>(self, transform: F) -> Self
where
R: OperationOutput,
F: Fn(TransformResponse<R::Inner>) -> TransformResponse<R::Inner> + Clone,
{
if let Some(p) = &mut self.api.paths {
for (_, p) in &mut p.paths {
let p = match p {
ReferenceOr::Reference { .. } => continue,
ReferenceOr::Item(p) => p,
};
for (_, op) in iter_operations_mut(p) {
let _ = TransformOperation::new(op)
.default_response_with::<R, F>(transform.clone());
}
}
}
self
}
#[allow(clippy::missing_panics_doc)]
pub fn security_scheme(mut self, name: &str, scheme: SecurityScheme) -> Self {
let components = match &mut self.inner_mut().components {
Some(c) => c,
None => {
self.inner_mut().components = Some(Components::default());
self.inner_mut().components.as_mut().unwrap()
}
};
components
.security_schemes
.insert(name.into(), ReferenceOr::Item(scheme));
self
}
#[tracing::instrument(skip_all)]
pub fn security_requirement(self, security_scheme: &str) -> Self {
self.security_requirement_multi([security_scheme])
}
#[tracing::instrument(skip_all)]
pub fn security_requirement_multi<'a, I>(mut self, security_schemes: I) -> Self
where
I: IntoIterator<Item = &'a str> + Clone,
{
if self.inner_mut().security.iter().any(|s| {
s.len() == security_schemes.clone().into_iter().count()
&& security_schemes
.clone()
.into_iter()
.all(|security_scheme| s.contains_key(security_scheme))
}) {
return self;
}
self.inner_mut().security.push(
security_schemes
.into_iter()
.map(|security_scheme| (security_scheme.to_string(), Vec::new()))
.collect(),
);
self
}
#[tracing::instrument(skip_all)]
#[allow(clippy::missing_panics_doc)]
pub fn security_requirement_scopes<I, S>(self, security_scheme: &str, scopes: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.security_requirement_multi_scopes([security_scheme], scopes)
}
#[tracing::instrument(skip_all)]
#[allow(clippy::missing_panics_doc)]
pub fn security_requirement_multi_scopes<'a, I, IS, S>(
mut self,
security_schemes: I,
scopes: IS,
) -> Self
where
I: IntoIterator<Item = &'a str> + Clone,
IS: IntoIterator<Item = S>,
S: Into<String>,
{
match self.inner_mut().security.iter_mut().find(|s| {
s.len() == security_schemes.clone().into_iter().count()
&& security_schemes
.clone()
.into_iter()
.all(|security_scheme| s.contains_key(security_scheme))
}) {
Some(s) => {
let scopes: Vec<String> = scopes.into_iter().map(Into::into).collect();
s.iter_mut().for_each(|(_, s)| s.extend(scopes.clone()));
}
None => {
let scopes: Vec<String> = scopes.into_iter().map(Into::into).collect();
self.inner_mut().security.push(
security_schemes
.into_iter()
.map(|security_scheme| (security_scheme.to_string(), scopes.clone()))
.collect(),
);
}
};
self
}
pub fn with(self, transform: impl FnOnce(Self) -> Self) -> Self {
transform(self)
}
#[inline]
pub fn inner_mut(&mut self) -> &mut OpenApi {
self.api
}
}
#[must_use]
pub struct TransformPathItem<'t> {
pub(crate) hidden: bool,
pub(crate) path: &'t mut PathItem,
}
impl<'t> TransformPathItem<'t> {
pub fn new(path: &'t mut PathItem) -> Self {
Self {
hidden: false,
path,
}
}
#[tracing::instrument(skip_all)]
pub fn hidden(mut self, hidden: bool) -> Self {
self.hidden = hidden;
self
}
#[tracing::instrument(skip_all)]
pub fn summary(self, desc: &str) -> Self {
self.path.summary = Some(desc.into());
self
}
#[tracing::instrument(skip_all)]
pub fn description(self, desc: &str) -> Self {
self.path.description = Some(desc.into());
self
}
#[tracing::instrument(skip_all)]
pub fn tag(self, tag: &str) -> Self {
for (_, op) in iter_operations_mut(self.path) {
if !op.tags.iter().any(|t| t == tag) {
op.tags.push(tag.into());
}
}
self
}
#[tracing::instrument(skip_all)]
pub fn default_response<R>(self) -> Self
where
R: OperationOutput,
{
in_context(|ctx| ctx.show_error = filter_no_duplicate_response);
for (_, op) in iter_operations_mut(self.path) {
let _ = TransformOperation::new(op).default_response::<R>();
}
in_context(GenContext::reset_error_filter);
self
}
#[tracing::instrument(skip_all)]
pub fn default_response_with<R, F>(self, transform: F) -> Self
where
R: OperationOutput,
F: Fn(TransformResponse<R::Inner>) -> TransformResponse<R::Inner> + Clone,
{
in_context(|ctx| ctx.show_error = filter_no_duplicate_response);
for (_, op) in iter_operations_mut(self.path) {
let _ = TransformOperation::new(op).default_response_with::<R, F>(transform.clone());
}
in_context(GenContext::reset_error_filter);
self
}
#[tracing::instrument(skip_all)]
pub fn security_requirement(self, security_scheme: &str) -> Self {
self.security_requirement_multi([security_scheme])
}
#[tracing::instrument(skip_all)]
pub fn security_requirement_multi<'a, I>(self, security_schemes: I) -> Self
where
I: IntoIterator<Item = &'a str> + Clone,
{
for (_, op) in iter_operations_mut(self.path) {
let _ =
TransformOperation::new(op).security_requirement_multi(security_schemes.clone());
}
self
}
#[tracing::instrument(skip_all)]
#[allow(clippy::missing_panics_doc)]
pub fn security_requirement_scopes<I, S>(self, security_scheme: &str, scopes: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.security_requirement_multi_scopes([security_scheme], scopes)
}
#[tracing::instrument(skip_all)]
#[allow(clippy::missing_panics_doc)]
pub fn security_requirement_multi_scopes<'a, I, IS, S>(
self,
security_schemes: I,
scopes: IS,
) -> Self
where
I: IntoIterator<Item = &'a str> + Clone,
IS: IntoIterator<Item = S>,
S: Into<String>,
{
let scopes: Vec<String> = scopes.into_iter().map(Into::into).collect();
for (_, op) in iter_operations_mut(self.path) {
let _ = TransformOperation::new(op)
.security_requirement_multi_scopes(security_schemes.clone(), scopes.clone());
}
self
}
pub fn with(self, transform: impl FnOnce(Self) -> Self) -> Self {
transform(self)
}
#[inline]
pub fn inner_mut(&mut self) -> &mut PathItem {
self.path
}
}
#[must_use]
pub struct TransformOperation<'t> {
pub(crate) hidden: bool,
pub(crate) operation: &'t mut Operation,
}
impl<'t> TransformOperation<'t> {
pub fn new(operation: &'t mut Operation) -> Self {
Self {
hidden: false,
operation,
}
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
pub fn id(self, name: &str) -> Self {
self.operation.operation_id = Some(name.into());
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
pub fn summary(self, desc: &str) -> Self {
self.operation.summary = Some(desc.into());
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
pub fn description(self, desc: &str) -> Self {
self.operation.description = Some(desc.into());
self
}
#[tracing::instrument(skip_all)]
pub fn tag(self, tag: &str) -> Self {
if !self.operation.tags.iter().any(|t| t == tag) {
self.operation.tags.push(tag.into());
}
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
pub fn hidden(mut self, hidden: bool) -> Self {
self.hidden = hidden;
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
pub fn input<T: OperationInput>(self) -> Self {
in_context(|ctx| {
T::operation_input(ctx, self.operation);
});
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
pub fn parameter<T, F>(self, name: &str, transform: F) -> Self
where
T: Serialize,
F: FnOnce(TransformParameter<T>) -> TransformParameter<T>,
{
let (idx, param) = match self
.operation
.parameters
.iter_mut()
.enumerate()
.find(|(_, p)| match p {
ReferenceOr::Item(p) => p.parameter_data_ref().name == name,
ReferenceOr::Reference { .. } => false,
}) {
Some((idx, p)) => match p {
ReferenceOr::Item(p) => (idx, p),
ReferenceOr::Reference { .. } => {
in_context(|ctx| {
ctx.error(Error::UnexpectedReference);
});
return self;
}
},
None => {
in_context(|ctx| {
ctx.error(Error::ParameterNotExists(name.to_string()));
});
return self;
}
};
let t = transform(TransformParameter::new(param));
if t.hidden {
self.operation.parameters.remove(idx);
}
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
pub fn parameter_untyped<F>(self, name: &str, transform: F) -> Self
where
F: FnOnce(TransformParameter<()>) -> TransformParameter<()>,
{
self.parameter(name, transform)
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
#[allow(clippy::missing_panics_doc)]
pub fn default_response<R>(self) -> Self
where
R: OperationOutput,
{
if self.operation.responses.is_none() {
self.operation.responses = Some(Default::default());
}
in_context(|ctx| {
if let Some(res) = R::operation_response(ctx, self.operation) {
let responses = self.operation.responses.as_mut().unwrap();
if responses.default.is_none() {
responses.default = Some(ReferenceOr::Item(res));
} else {
ctx.error(Error::DefaultResponseExists);
}
} else {
tracing::debug!(type_name = type_name::<R>(), "no response info of type");
}
});
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
#[allow(clippy::missing_panics_doc)]
pub fn default_response_with<R, F>(self, transform: F) -> Self
where
R: OperationOutput,
F: FnOnce(TransformResponse<R::Inner>) -> TransformResponse<R::Inner>,
{
if self.operation.responses.is_none() {
self.operation.responses = Some(Default::default());
} else {
tracing::trace!("operation already has a default response");
}
in_context(|ctx| {
if let Some(mut res) = R::operation_response(ctx, self.operation) {
let responses = self.operation.responses.as_mut().unwrap();
if responses.default.is_none() {
let t = transform(TransformResponse::new(&mut res));
if !t.hidden {
responses.default = Some(ReferenceOr::Item(res));
}
} else {
ctx.error(Error::DefaultResponseExists);
}
} else {
tracing::debug!(type_name = type_name::<R>(), "no response info of type");
}
});
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
#[allow(clippy::missing_panics_doc)]
pub fn response<const N: u16, R>(self) -> Self
where
R: OperationOutput,
{
if self.operation.responses.is_none() {
self.operation.responses = Some(Default::default());
}
in_context(|ctx| {
if let Some(res) = R::operation_response(ctx, self.operation) {
let responses = self.operation.responses.as_mut().unwrap();
if responses
.responses
.insert(StatusCode::Code(N), ReferenceOr::Item(res))
.is_some()
{
ctx.error(Error::ResponseExists(StatusCode::Code(N)));
};
} else {
tracing::debug!(type_name = type_name::<R>(), "no response info of type");
}
});
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
#[allow(clippy::missing_panics_doc)]
pub fn response_with<const N: u16, R, F>(self, transform: F) -> Self
where
R: OperationOutput,
F: FnOnce(TransformResponse<R::Inner>) -> TransformResponse<R::Inner>,
{
if self.operation.responses.is_none() {
self.operation.responses = Some(Default::default());
}
in_context(|ctx| {
if let Some(mut res) = R::operation_response(ctx, self.operation) {
let t = transform(TransformResponse::new(&mut res));
let responses = self.operation.responses.as_mut().unwrap();
if !t.hidden {
let existing = responses
.responses
.insert(StatusCode::Code(N), ReferenceOr::Item(res))
.is_some();
if existing {
ctx.error(Error::ResponseExists(StatusCode::Code(N)));
};
}
} else {
tracing::debug!(type_name = type_name::<R>(), "no response info of type");
}
});
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
#[allow(clippy::missing_panics_doc)]
pub fn response_range<const N: u16, R>(self) -> Self
where
R: OperationOutput,
{
if self.operation.responses.is_none() {
self.operation.responses = Some(Default::default());
}
in_context(|ctx| {
if let Some(res) = R::operation_response(ctx, self.operation) {
let responses = self.operation.responses.as_mut().unwrap();
if responses
.responses
.insert(StatusCode::Range(N), ReferenceOr::Item(res))
.is_some()
{
ctx.error(Error::ResponseExists(StatusCode::Range(N)));
};
} else {
tracing::debug!(type_name = type_name::<R>(), "no response info of type");
}
});
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
#[allow(clippy::missing_panics_doc)]
pub fn response_range_with<const N: u16, R, F>(self, transform: F) -> Self
where
R: OperationOutput,
F: FnOnce(TransformResponse<R::Inner>) -> TransformResponse<R::Inner>,
{
if self.operation.responses.is_none() {
self.operation.responses = Some(Default::default());
}
in_context(|ctx| {
if let Some(mut res) = R::operation_response(ctx, self.operation) {
let t = transform(TransformResponse::new(&mut res));
let responses = self.operation.responses.as_mut().unwrap();
if !t.hidden {
let existing = responses
.responses
.insert(StatusCode::Range(N), ReferenceOr::Item(res))
.is_some();
if existing {
ctx.error(Error::ResponseExists(StatusCode::Range(N)));
};
}
} else {
tracing::debug!(type_name = type_name::<R>(), "no response info of type");
}
});
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
#[allow(clippy::missing_panics_doc)]
pub fn callback(
self,
callback_name: &str,
callback_url: &str,
callback_transform: impl FnOnce(TransformCallback) -> TransformCallback,
) -> Self {
let callbacks = self
.operation
.callbacks
.entry(callback_name.to_string())
.or_insert_with(|| ReferenceOr::Item(IndexMap::default()));
let callbacks = match callbacks {
ReferenceOr::Reference { .. } => {
in_context(|ctx| ctx.error(Error::UnexpectedReference));
return self;
}
ReferenceOr::Item(cbs) => cbs,
};
let p = callbacks
.entry(callback_url.to_string())
.or_insert_with(|| ReferenceOr::Item(PathItem::default()));
let p = match p {
ReferenceOr::Reference { .. } => {
in_context(|ctx| ctx.error(Error::UnexpectedReference));
return self;
}
ReferenceOr::Item(p) => p,
};
let t = callback_transform(TransformCallback::new(p));
if t.hidden {
callbacks.remove(callback_url);
if self
.operation
.callbacks
.get(callback_name)
.unwrap()
.as_item()
.unwrap()
.is_empty()
{
self.operation.callbacks.remove(callback_name);
}
}
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
pub fn security_requirement(self, security_scheme: &str) -> Self {
self.security_requirement_multi([security_scheme])
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
pub fn security_requirement_multi<'a, I>(self, security_schemes: I) -> Self
where
I: IntoIterator<Item = &'a str> + Clone,
{
if self.operation.security.iter().any(|s| {
s.len() == security_schemes.clone().into_iter().count()
&& security_schemes
.clone()
.into_iter()
.all(|security_scheme| s.contains_key(security_scheme))
}) {
return self;
}
self.operation.security.push(
security_schemes
.into_iter()
.map(|security_scheme| (security_scheme.to_string(), Vec::new()))
.collect(),
);
self
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
#[allow(clippy::missing_panics_doc)]
pub fn security_requirement_scopes<I, S>(self, security_scheme: &str, scopes: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.security_requirement_multi_scopes([security_scheme], scopes)
}
#[tracing::instrument(skip_all, fields(operation_id = ?self.operation.operation_id))]
#[allow(clippy::missing_panics_doc)]
pub fn security_requirement_multi_scopes<'a, I, IS, S>(
self,
security_schemes: I,
scopes: IS,
) -> Self
where
I: IntoIterator<Item = &'a str> + Clone,
IS: IntoIterator<Item = S>,
S: Into<String>,
{
match self.operation.security.iter_mut().find(|s| {
s.len() == security_schemes.clone().into_iter().count()
&& security_schemes
.clone()
.into_iter()
.all(|security_scheme| s.contains_key(security_scheme))
}) {
Some(s) => {
let scopes: Vec<String> = scopes.into_iter().map(Into::into).collect();
s.iter_mut().for_each(|(_, s)| s.extend(scopes.clone()));
}
None => {
let scopes: Vec<String> = scopes.into_iter().map(Into::into).collect();
self.operation.security.push(
security_schemes
.into_iter()
.map(|security_scheme| (security_scheme.to_string(), scopes.clone()))
.collect(),
);
}
};
self
}
pub fn with(self, transform: impl FnOnce(Self) -> Self) -> Self {
transform(self)
}
#[inline]
pub fn inner_mut(&mut self) -> &mut Operation {
self.operation
}
}
#[must_use]
pub struct TransformParameter<'t, T> {
pub(crate) hidden: bool,
pub(crate) param: &'t mut Parameter,
_t: PhantomData<T>,
}
impl<'t, T> TransformParameter<'t, T> {
pub fn new(param: &'t mut Parameter) -> Self {
Self {
hidden: false,
param,
_t: PhantomData,
}
}
#[tracing::instrument(skip_all)]
pub fn hidden(mut self, hidden: bool) -> Self {
self.hidden = hidden;
self
}
#[tracing::instrument(skip_all)]
pub fn description(mut self, desc: &str) -> Self {
let data = match &mut self.param {
Parameter::Query { parameter_data, .. }
| Parameter::Header { parameter_data, .. }
| Parameter::Path { parameter_data, .. }
| Parameter::Cookie { parameter_data, .. } => parameter_data,
};
data.description = Some(desc.into());
self
}
pub fn with(self, transform: impl FnOnce(Self) -> Self) -> Self {
transform(self)
}
#[inline]
pub fn inner_mut(&mut self) -> &mut Parameter {
self.param
}
}
#[must_use]
pub struct TransformResponse<'t, T> {
pub(crate) hidden: bool,
pub(crate) response: &'t mut Response,
_t: PhantomData<T>,
}
impl<'t, T> TransformResponse<'t, T> {
pub fn new(response: &'t mut Response) -> Self {
Self {
hidden: false,
response,
_t: PhantomData,
}
}
#[tracing::instrument(skip_all)]
pub fn hidden(mut self, hidden: bool) -> Self {
self.hidden = hidden;
self
}
#[tracing::instrument(skip_all)]
pub fn description(self, desc: &str) -> Self {
self.response.description = desc.into();
self
}
#[tracing::instrument(skip_all)]
#[allow(clippy::missing_panics_doc)]
pub fn example(self, example: impl Into<T>) -> Self
where
T: Serialize,
{
let example = example.into();
for (_, c) in &mut self.response.content {
c.example = Some(serde_json::to_value(&example).unwrap());
}
self
}
pub fn with(self, transform: impl FnOnce(Self) -> Self) -> Self {
transform(self)
}
pub fn inner(&mut self) -> &mut Response {
self.response
}
}
#[must_use]
pub struct TransformCallback<'t> {
hidden: bool,
path: &'t mut PathItem,
}
impl<'t> TransformCallback<'t> {
pub fn new(path: &'t mut PathItem) -> Self {
Self {
hidden: false,
path,
}
}
pub fn hidden(mut self, hidden: bool) -> Self {
self.hidden = hidden;
self
}
#[allow(clippy::missing_panics_doc)]
pub fn delete(self, operation: impl FnOnce(TransformOperation) -> TransformOperation) -> Self {
let op = match &mut self.path.delete {
Some(op) => op,
None => {
self.path.delete = Some(Operation::default());
self.path.delete.as_mut().unwrap()
}
};
let t = operation(TransformOperation::new(op));
if t.hidden {
self.path.delete = None;
}
self
}
#[allow(clippy::missing_panics_doc)]
pub fn get(self, operation: impl FnOnce(TransformOperation) -> TransformOperation) -> Self {
let op = match &mut self.path.get {
Some(op) => op,
None => {
self.path.get = Some(Operation::default());
self.path.get.as_mut().unwrap()
}
};
let t = operation(TransformOperation::new(op));
if t.hidden {
self.path.get = None;
}
self
}
#[allow(clippy::missing_panics_doc)]
pub fn head(self, operation: impl FnOnce(TransformOperation) -> TransformOperation) -> Self {
let op = match &mut self.path.head {
Some(op) => op,
None => {
self.path.head = Some(Operation::default());
self.path.head.as_mut().unwrap()
}
};
let t = operation(TransformOperation::new(op));
if t.hidden {
self.path.head = None;
}
self
}
#[allow(clippy::missing_panics_doc)]
pub fn options(self, operation: impl FnOnce(TransformOperation) -> TransformOperation) -> Self {
let op = match &mut self.path.options {
Some(op) => op,
None => {
self.path.options = Some(Operation::default());
self.path.options.as_mut().unwrap()
}
};
let t = operation(TransformOperation::new(op));
if t.hidden {
self.path.options = None;
}
self
}
#[allow(clippy::missing_panics_doc)]
pub fn patch(self, operation: impl FnOnce(TransformOperation) -> TransformOperation) -> Self {
let op = match &mut self.path.patch {
Some(op) => op,
None => {
self.path.patch = Some(Operation::default());
self.path.patch.as_mut().unwrap()
}
};
let t = operation(TransformOperation::new(op));
if t.hidden {
self.path.patch = None;
}
self
}
#[allow(clippy::missing_panics_doc)]
pub fn post(self, operation: impl FnOnce(TransformOperation) -> TransformOperation) -> Self {
let op = match &mut self.path.post {
Some(op) => op,
None => {
self.path.post = Some(Operation::default());
self.path.post.as_mut().unwrap()
}
};
let t = operation(TransformOperation::new(op));
if t.hidden {
self.path.post = None;
}
self
}
#[allow(clippy::missing_panics_doc)]
pub fn put(self, operation: impl FnOnce(TransformOperation) -> TransformOperation) -> Self {
let op = match &mut self.path.put {
Some(op) => op,
None => {
self.path.put = Some(Operation::default());
self.path.put.as_mut().unwrap()
}
};
let t = operation(TransformOperation::new(op));
if t.hidden {
self.path.put = None;
}
self
}
#[allow(clippy::missing_panics_doc)]
pub fn trace(self, operation: impl FnOnce(TransformOperation) -> TransformOperation) -> Self {
let op = match &mut self.path.trace {
Some(op) => op,
None => {
self.path.trace = Some(Operation::default());
self.path.trace.as_mut().unwrap()
}
};
let t = operation(TransformOperation::new(op));
if t.hidden {
self.path.trace = None;
}
self
}
pub fn path(mut self, transform: impl FnOnce(TransformPathItem) -> TransformPathItem) -> Self {
let t = transform(TransformPathItem::new(self.path));
if t.hidden {
self.hidden = true;
}
self
}
pub fn with(self, transform: impl FnOnce(Self) -> Self) -> Self {
transform(self)
}
}
fn filter_no_duplicate_response(err: &Error) -> bool {
!matches!(err, Error::DefaultResponseExists | Error::ResponseExists(_))
}