mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-05-12 20:50:55 +00:00
[Rust] [Server] New generator bases on Axum (#17549)
* Rust Server - Axum based (#5) * Fix typo * Address comment * Address comment
This commit is contained in:
parent
210044eb8a
commit
9827098057
3
.github/workflows/samples-rust.yaml
vendored
3
.github/workflows/samples-rust.yaml
vendored
@ -6,11 +6,13 @@ on:
|
||||
- "samples/client/others/rust/**"
|
||||
- "samples/server/petstore/rust-server/**"
|
||||
- "samples/client/petstore/rust-server/**"
|
||||
- "samples/server/petstore/rust-axum/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- "samples/client/others/rust/**"
|
||||
- "samples/client/petstore/rust/**"
|
||||
- "samples/server/petstore/rust-server/**"
|
||||
- "samples/server/petstore/rust-axum/**"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -24,6 +26,7 @@ jobs:
|
||||
- samples/client/others/rust/
|
||||
- samples/client/petstore/rust/
|
||||
- samples/server/petstore/rust-server/
|
||||
- samples/server/petstore/rust-axum/
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions-rs/toolchain@v1
|
||||
|
@ -22,6 +22,7 @@ cache:
|
||||
- $HOME/samples/client/petstore/ruby/vendor/bundle
|
||||
- $HOME/samples/client/petstore/python/.venv/
|
||||
- $HOME/samples/server/petstore/rust-server/target
|
||||
- $HOME/samples/server/petstore/rust-axum/target
|
||||
- $HOME/perl5
|
||||
- $HOME/.cargo
|
||||
- $HOME/.pub-cache
|
||||
|
10
bin/configs/rust-axum-multipart-v3.yaml
Normal file
10
bin/configs/rust-axum-multipart-v3.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
generatorName: rust-axum
|
||||
outputDir: samples/server/petstore/rust-axum/output/multipart-v3
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/rust-server/multipart-v3.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/rust-axum
|
||||
generateAliasAsModel: true
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
||||
allowBlockingResponseSerialize: "true"
|
||||
packageName: multipart-v3
|
||||
enablePostProcessFile: true
|
10
bin/configs/rust-axum-openapi-v3.yaml
Normal file
10
bin/configs/rust-axum-openapi-v3.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
generatorName: rust-axum
|
||||
outputDir: samples/server/petstore/rust-axum/output/openapi-v3
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/rust-server/openapi-v3.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/rust-axum
|
||||
generateAliasAsModel: true
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
||||
allowBlockingValidator: "true"
|
||||
packageName: openapi-v3
|
||||
enablePostProcessFile: true
|
8
bin/configs/rust-axum-ops-v3.yaml
Normal file
8
bin/configs/rust-axum-ops-v3.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
generatorName: rust-axum
|
||||
outputDir: samples/server/petstore/rust-axum/output/ops-v3
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/rust-server/ops-v3.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/rust-axum
|
||||
generateAliasAsModel: true
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
||||
packageName: ops-v3
|
@ -0,0 +1,10 @@
|
||||
generatorName: rust-axum
|
||||
outputDir: samples/server/petstore/rust-axum/output/petstore-with-fake-endpoints-models-for-testing
|
||||
inputSpec: modules/openapi-generator/src/test/resources/2_0/rust-server/petstore-with-fake-endpoints-models-for-testing.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/rust-axum
|
||||
generateAliasAsModel: true
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
||||
packageName: petstore-with-fake-endpoints-models-for-testing
|
||||
publishRustRegistry: crates-io
|
||||
enablePostProcessFile: true
|
9
bin/configs/rust-axum-petstore.yaml
Normal file
9
bin/configs/rust-axum-petstore.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
generatorName: rust-axum
|
||||
outputDir: samples/server/petstore/rust-axum/output/petstore
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/rust-axum
|
||||
generateAliasAsModel: true
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
||||
packageName: petstore
|
||||
enablePostProcessFile: true
|
9
bin/configs/rust-axum-ping-bearer-auth-v3.yaml
Normal file
9
bin/configs/rust-axum-ping-bearer-auth-v3.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
generatorName: rust-axum
|
||||
outputDir: samples/server/petstore/rust-axum/output/ping-bearer-auth
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/rust-server/ping-bearer-auth.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/rust-axum
|
||||
generateAliasAsModel: true
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
||||
packageName: ping-bearer-auth
|
||||
enablePostProcessFile: true
|
9
bin/configs/rust-axum-test.yaml
Normal file
9
bin/configs/rust-axum-test.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
generatorName: rust-axum
|
||||
outputDir: samples/server/petstore/rust-axum/output/rust-axum-test
|
||||
inputSpec: modules/openapi-generator/src/test/resources/2_0/rust-server/rust-server-test.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/rust-axum
|
||||
generateAliasAsModel: true
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
||||
packageName: rust-server-test
|
||||
enablePostProcessFile: true
|
@ -130,6 +130,7 @@ The following generators are available:
|
||||
* [python-flask](generators/python-flask.md)
|
||||
* [ruby-on-rails](generators/ruby-on-rails.md)
|
||||
* [ruby-sinatra](generators/ruby-sinatra.md)
|
||||
* [rust-axum (beta)](generators/rust-axum.md)
|
||||
* [rust-server](generators/rust-server.md)
|
||||
* [scala-akka-http-server (beta)](generators/scala-akka-http-server.md)
|
||||
* [scala-finch](generators/scala-finch.md)
|
||||
|
235
docs/generators/rust-axum.md
Normal file
235
docs/generators/rust-axum.md
Normal file
@ -0,0 +1,235 @@
|
||||
---
|
||||
title: Documentation for the rust-axum Generator
|
||||
---
|
||||
|
||||
## METADATA
|
||||
|
||||
| Property | Value | Notes |
|
||||
| -------- | ----- | ----- |
|
||||
| generator name | rust-axum | pass this to the generate command after -g |
|
||||
| generator stability | BETA | |
|
||||
| generator type | SERVER | |
|
||||
| generator language | Rust | |
|
||||
| generator default templating engine | mustache | |
|
||||
| helpTxt | Generates a Rust server library which bases on Axum. | |
|
||||
|
||||
## CONFIG OPTIONS
|
||||
These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
|
||||
|
||||
| Option | Description | Values | Default |
|
||||
| ------ | ----------- | ------ | ------- |
|
||||
|allowBlockingResponseSerialize|By default, json/form-urlencoded response serialization, which might perform a lot of compute in a future without yielding, is executed on a blocking thread via tokio::task::spawn_blocking. Set this option to true will override this behaviour and allow blocking call to happen. It helps to improve the performance when response serialization (e.g. returns tiny data) is low cost.| |false|
|
||||
|allowBlockingValidator|By default, validation process, which might perform a lot of compute in a future without yielding, is executed on a blocking thread via tokio::task::spawn_blocking. Set this option to true will override this behaviour and allow blocking call to happen. It helps to improve the performance when validating request-data (header, path, query, body) is low cost.| |false|
|
||||
|disableValidator|Disable validating request-data (header, path, query, body) against OpenAPI Schema Specification.| |false|
|
||||
|packageName|Rust crate name (convention: snake_case).| |openapi|
|
||||
|packageVersion|Rust crate version.| |null|
|
||||
|
||||
## IMPORT MAPPING
|
||||
|
||||
| Type/Alias | Imports |
|
||||
| ---------- | ------- |
|
||||
|
||||
|
||||
## INSTANTIATION TYPES
|
||||
|
||||
| Type/Alias | Instantiated By |
|
||||
| ---------- | --------------- |
|
||||
|array|Vec|
|
||||
|map|std::collections::HashMap|
|
||||
|
||||
|
||||
## LANGUAGE PRIMITIVES
|
||||
|
||||
<ul class="column-ul">
|
||||
<li>String</li>
|
||||
<li>bool</li>
|
||||
<li>char</li>
|
||||
<li>f32</li>
|
||||
<li>f64</li>
|
||||
<li>i16</li>
|
||||
<li>i32</li>
|
||||
<li>i64</li>
|
||||
<li>i8</li>
|
||||
<li>isize</li>
|
||||
<li>str</li>
|
||||
<li>u16</li>
|
||||
<li>u32</li>
|
||||
<li>u64</li>
|
||||
<li>u8</li>
|
||||
<li>usize</li>
|
||||
</ul>
|
||||
|
||||
## RESERVED WORDS
|
||||
|
||||
<ul class="column-ul">
|
||||
<li>Self</li>
|
||||
<li>abstract</li>
|
||||
<li>as</li>
|
||||
<li>async</li>
|
||||
<li>await</li>
|
||||
<li>become</li>
|
||||
<li>box</li>
|
||||
<li>break</li>
|
||||
<li>const</li>
|
||||
<li>continue</li>
|
||||
<li>crate</li>
|
||||
<li>do</li>
|
||||
<li>dyn</li>
|
||||
<li>else</li>
|
||||
<li>enum</li>
|
||||
<li>extern</li>
|
||||
<li>false</li>
|
||||
<li>final</li>
|
||||
<li>fn</li>
|
||||
<li>for</li>
|
||||
<li>if</li>
|
||||
<li>impl</li>
|
||||
<li>in</li>
|
||||
<li>let</li>
|
||||
<li>loop</li>
|
||||
<li>macro</li>
|
||||
<li>match</li>
|
||||
<li>mod</li>
|
||||
<li>move</li>
|
||||
<li>mut</li>
|
||||
<li>override</li>
|
||||
<li>priv</li>
|
||||
<li>pub</li>
|
||||
<li>ref</li>
|
||||
<li>return</li>
|
||||
<li>self</li>
|
||||
<li>static</li>
|
||||
<li>struct</li>
|
||||
<li>super</li>
|
||||
<li>trait</li>
|
||||
<li>true</li>
|
||||
<li>try</li>
|
||||
<li>type</li>
|
||||
<li>typeof</li>
|
||||
<li>unsafe</li>
|
||||
<li>unsized</li>
|
||||
<li>use</li>
|
||||
<li>virtual</li>
|
||||
<li>where</li>
|
||||
<li>while</li>
|
||||
<li>yield</li>
|
||||
</ul>
|
||||
|
||||
## FEATURE SET
|
||||
|
||||
|
||||
### Client Modification Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|BasePath|✗|ToolingExtension
|
||||
|Authorizations|✗|ToolingExtension
|
||||
|UserAgent|✗|ToolingExtension
|
||||
|MockServer|✗|ToolingExtension
|
||||
|
||||
### Data Type Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|Custom|✗|OAS2,OAS3
|
||||
|Int32|✓|OAS2,OAS3
|
||||
|Int64|✓|OAS2,OAS3
|
||||
|Float|✓|OAS2,OAS3
|
||||
|Double|✓|OAS2,OAS3
|
||||
|Decimal|✓|ToolingExtension
|
||||
|String|✓|OAS2,OAS3
|
||||
|Byte|✓|OAS2,OAS3
|
||||
|Binary|✓|OAS2,OAS3
|
||||
|Boolean|✓|OAS2,OAS3
|
||||
|Date|✓|OAS2,OAS3
|
||||
|DateTime|✓|OAS2,OAS3
|
||||
|Password|✓|OAS2,OAS3
|
||||
|File|✓|OAS2
|
||||
|Uuid|✗|
|
||||
|Array|✓|OAS2,OAS3
|
||||
|Null|✗|OAS3
|
||||
|AnyType|✗|OAS2,OAS3
|
||||
|Object|✓|OAS2,OAS3
|
||||
|Maps|✓|ToolingExtension
|
||||
|CollectionFormat|✓|OAS2
|
||||
|CollectionFormatMulti|✓|OAS2
|
||||
|Enum|✓|OAS2,OAS3
|
||||
|ArrayOfEnum|✓|ToolingExtension
|
||||
|ArrayOfModel|✓|ToolingExtension
|
||||
|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
|
||||
|ArrayOfCollectionOfModel|✓|ToolingExtension
|
||||
|ArrayOfCollectionOfEnum|✓|ToolingExtension
|
||||
|MapOfEnum|✓|ToolingExtension
|
||||
|MapOfModel|✓|ToolingExtension
|
||||
|MapOfCollectionOfPrimitives|✓|ToolingExtension
|
||||
|MapOfCollectionOfModel|✓|ToolingExtension
|
||||
|MapOfCollectionOfEnum|✓|ToolingExtension
|
||||
|
||||
### Documentation Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|Readme|✗|ToolingExtension
|
||||
|Model|✓|ToolingExtension
|
||||
|Api|✓|ToolingExtension
|
||||
|
||||
### Global Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|Host|✓|OAS2,OAS3
|
||||
|BasePath|✓|OAS2,OAS3
|
||||
|Info|✗|OAS2,OAS3
|
||||
|Schemes|✗|OAS2,OAS3
|
||||
|PartialSchemes|✓|OAS2,OAS3
|
||||
|Consumes|✓|OAS2
|
||||
|Produces|✓|OAS2
|
||||
|ExternalDocumentation|✗|OAS2,OAS3
|
||||
|Examples|✗|OAS2,OAS3
|
||||
|XMLStructureDefinitions|✗|OAS2,OAS3
|
||||
|MultiServer|✗|OAS3
|
||||
|ParameterizedServer|✗|OAS3
|
||||
|ParameterStyling|✗|OAS3
|
||||
|Callbacks|✗|OAS3
|
||||
|LinkObjects|✗|OAS3
|
||||
|
||||
### Parameter Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|Path|✓|OAS2,OAS3
|
||||
|Query|✓|OAS2,OAS3
|
||||
|Header|✓|OAS2,OAS3
|
||||
|Body|✓|OAS2
|
||||
|FormUnencoded|✓|OAS2
|
||||
|FormMultipart|✓|OAS2
|
||||
|Cookie|✗|OAS3
|
||||
|
||||
### Schema Support Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|Simple|✓|OAS2,OAS3
|
||||
|Composite|✓|OAS2,OAS3
|
||||
|Polymorphism|✗|OAS2,OAS3
|
||||
|Union|✗|OAS3
|
||||
|allOf|✗|OAS2,OAS3
|
||||
|anyOf|✗|OAS3
|
||||
|oneOf|✗|OAS3
|
||||
|not|✗|OAS3
|
||||
|
||||
### Security Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|BasicAuth|✓|OAS2,OAS3
|
||||
|ApiKey|✓|OAS2,OAS3
|
||||
|OpenIDConnect|✗|OAS3
|
||||
|BearerToken|✓|OAS3
|
||||
|OAuth2_Implicit|✓|OAS2,OAS3
|
||||
|OAuth2_Password|✓|OAS2,OAS3
|
||||
|OAuth2_ClientCredentials|✓|OAS2,OAS3
|
||||
|OAuth2_AuthorizationCode|✓|OAS2,OAS3
|
||||
|SignatureAuth|✗|OAS3
|
||||
|AWSV4Signature|✗|ToolingExtension
|
||||
|
||||
### Wire Format Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|JSON|✓|OAS2,OAS3
|
||||
|XML|✗|OAS2,OAS3
|
||||
|PROTOBUF|✗|ToolingExtension
|
||||
|Custom|✓|OAS2,OAS3
|
File diff suppressed because it is too large
Load Diff
@ -143,3 +143,4 @@ org.openapitools.codegen.languages.TypeScriptRxjsClientCodegen
|
||||
org.openapitools.codegen.languages.WsdlSchemaCodegen
|
||||
org.openapitools.codegen.languages.XojoClientCodegen
|
||||
org.openapitools.codegen.languages.ZapierClientCodegen
|
||||
org.openapitools.codegen.languages.RustAxumServerCodegen
|
||||
|
68
modules/openapi-generator/src/main/resources/rust-axum/Cargo.mustache
vendored
Normal file
68
modules/openapi-generator/src/main/resources/rust-axum/Cargo.mustache
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
[package]
|
||||
name = "{{{packageName}}}"
|
||||
version = "{{{packageVersion}}}"
|
||||
{{#infoEmail}}
|
||||
authors = ["{{{.}}}"]
|
||||
{{/infoEmail}}
|
||||
{{^infoEmail}}
|
||||
authors = ["OpenAPI Generator team and contributors"]
|
||||
{{/infoEmail}}
|
||||
{{#appDescription}}
|
||||
description = "{{{.}}}"
|
||||
{{/appDescription}}
|
||||
{{#licenseInfo}}
|
||||
license = "{{.}}"
|
||||
{{/licenseInfo}}
|
||||
edition = "2021"
|
||||
{{#publishRustRegistry}}
|
||||
publish = ["{{.}}"]
|
||||
{{/publishRustRegistry}}
|
||||
{{#repositoryUrl}}
|
||||
repository = "{{.}}"
|
||||
{{/repositoryUrl}}
|
||||
{{#documentationUrl}}
|
||||
documentation = "{{.}}"
|
||||
{{/documentationUrl}}
|
||||
{{#homePageUrl}}
|
||||
homepage = "{{.}}
|
||||
{{/homePageUrl}}
|
||||
|
||||
[features]
|
||||
default = ["server"]
|
||||
server = []
|
||||
conversion = [
|
||||
"frunk",
|
||||
"frunk_derives",
|
||||
"frunk_core",
|
||||
"frunk-enum-core",
|
||||
"frunk-enum-derive",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
axum = { version = "0.7" }
|
||||
axum-extra = { version = "0.9", features = ["cookie", "multipart"] }
|
||||
base64 = "0.21"
|
||||
bytes = "1"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
frunk = { version = "0.4", optional = true }
|
||||
frunk-enum-core = { version = "0.3", optional = true }
|
||||
frunk-enum-derive = { version = "0.3", optional = true }
|
||||
frunk_core = { version = "0.4", optional = true }
|
||||
frunk_derives = { version = "0.4", optional = true }
|
||||
http = "1"
|
||||
lazy_static = "1"
|
||||
regex = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
serde_urlencoded = "0.7"
|
||||
tokio = { version = "1", default-features = false, features = [
|
||||
"signal",
|
||||
"rt-multi-thread",
|
||||
] }
|
||||
tracing = { version = "0.1", features = ["attributes"] }
|
||||
uuid = { version = "1", features = ["serde"] }
|
||||
validator = { version = "0.16", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = "0.3"
|
@ -0,0 +1,19 @@
|
||||
# Rust Axum Server Generator Templates
|
||||
|
||||
The Rust Axum Server Generator templates use Mustache Partials.
|
||||
|
||||
The following tree shows which templates include which:
|
||||
|
||||
- `Cargo.mustache`
|
||||
- `gitignore`
|
||||
- `header.mustache`
|
||||
- `lib.mustache`
|
||||
- `response.mustache`
|
||||
- `models.mustache`
|
||||
- `README.mustache`
|
||||
- `server-mod.mustache`
|
||||
- `server-imports.mustache`
|
||||
- `server-route.mustache`
|
||||
- `server-operation-validate.mustache`
|
||||
- `server-operation.mustache`
|
||||
- `types.mustache`
|
93
modules/openapi-generator/src/main/resources/rust-axum/README.mustache
vendored
Normal file
93
modules/openapi-generator/src/main/resources/rust-axum/README.mustache
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
# Rust API for {{{packageName}}}
|
||||
|
||||
{{#appDescriptionWithNewLines}}
|
||||
{{{.}}}
|
||||
{{/appDescriptionWithNewLines}}
|
||||
|
||||
## Overview
|
||||
|
||||
This server was generated by the [openapi-generator]
|
||||
(https://openapi-generator.tech) project. By using the
|
||||
[OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
|
||||
server, you can easily generate a server stub.
|
||||
|
||||
To see how to make this your own, look here: [README]((https://openapi-generator.tech))
|
||||
|
||||
- API version: {{{appVersion}}}
|
||||
{{^hideGenerationTimestamp}}- Build date: {{{generatedDate}}}{{/hideGenerationTimestamp}}
|
||||
|
||||
{{#infoUrl}}For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}){{/infoUrl}}
|
||||
|
||||
This autogenerated project defines an API crate `{{{packageName}}}` which contains:
|
||||
* An `Api` trait defining the API in Rust.
|
||||
* Data types representing the underlying data model.
|
||||
* Axum router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
|
||||
* Request validations (path, query, body params) are included.
|
||||
|
||||
## Using the generated library
|
||||
|
||||
The generated library has a few optional features that can be activated through Cargo.
|
||||
|
||||
* `server`
|
||||
* This defaults to enabled and creates the basic skeleton of a server implementation based on Axum.
|
||||
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
|
||||
* `conversions`
|
||||
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
|
||||
|
||||
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
|
||||
|
||||
### Example
|
||||
|
||||
```rust
|
||||
struct ServerImpl {
|
||||
// database: sea_orm::DbConn,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[async_trait]
|
||||
impl {{{packageName}}}::Api for ServerImpl {
|
||||
// API implementation goes here
|
||||
}
|
||||
|
||||
pub async fn start_server(addr: &str) {
|
||||
// initialize tracing
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// Init Axum router
|
||||
let app = {{{packageName}}}::server::new(Arc::new(ServerImpl));
|
||||
|
||||
// Add layers to the router
|
||||
let app = app.layer(...);
|
||||
|
||||
// Run the server with graceful shutdown
|
||||
let listener = TcpListener::bind(addr).await.unwrap();
|
||||
axum::serve(listener, app)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
180
modules/openapi-generator/src/main/resources/rust-axum/header.mustache
vendored
Normal file
180
modules/openapi-generator/src/main/resources/rust-axum/header.mustache
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
use std::{convert::TryFrom, fmt, ops::Deref};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use http::HeaderValue;
|
||||
|
||||
/// A struct to allow homogeneous conversion into a HeaderValue. We can't
|
||||
/// implement the From/Into trait on HeaderValue because we don't own
|
||||
/// either of the types.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct IntoHeaderValue<T>(pub T);
|
||||
|
||||
// Generic implementations
|
||||
|
||||
impl<T> Deref for IntoHeaderValue<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
// Derive for each TryFrom<T> in http::HeaderValue
|
||||
|
||||
macro_rules! ihv_generate {
|
||||
($t:ident) => {
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<$t> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse::<$t>() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!("Unable to parse {} as a string: {}",
|
||||
stringify!($t), e)),
|
||||
},
|
||||
Err(e) => Err(format!("Unable to parse header {:?} as a string - {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<$t>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<$t>) -> Result<Self, Self::Error> {
|
||||
Ok(hdr_value.0.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ihv_generate!(u64);
|
||||
ihv_generate!(i64);
|
||||
ihv_generate!(i16);
|
||||
ihv_generate!(u16);
|
||||
ihv_generate!(u32);
|
||||
ihv_generate!(usize);
|
||||
ihv_generate!(isize);
|
||||
ihv_generate!(i32);
|
||||
|
||||
// Custom derivations
|
||||
|
||||
// Vec<String>
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<Vec<String>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(
|
||||
hdr_value
|
||||
.split(',')
|
||||
.filter_map(|x| match x.trim() {
|
||||
"" => None,
|
||||
y => Some(y.to_string()),
|
||||
})
|
||||
.collect())),
|
||||
Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<Vec<String>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<Vec<String>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.join(", ")) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!("Unable to convert {:?} into a header - {}",
|
||||
hdr_value, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<String> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())),
|
||||
Err(e) => Err(format!("Unable to convert header {:?} to {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<String>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<String>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!("Unable to convert {:?} from a header {}",
|
||||
hdr_value, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bool
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<bool> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!("Unable to parse bool from {} - {}",
|
||||
hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!("Unable to convert {:?} from a header {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<bool>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<bool>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.to_string()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!("Unable to convert: {:?} into a header: {}",
|
||||
hdr_value, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DateTime
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<DateTime<Utc>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) {
|
||||
Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))),
|
||||
Err(e) => Err(format!("Unable to parse: {} as date - {}",
|
||||
hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!("Unable to convert header {:?} to string {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<DateTime<Utc>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<DateTime<Utc>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!("Unable to convert {:?} to a header: {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
99
modules/openapi-generator/src/main/resources/rust-axum/lib.mustache
vendored
Normal file
99
modules/openapi-generator/src/main/resources/rust-axum/lib.mustache
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
|
||||
#![allow(unused_imports, unused_attributes)]
|
||||
#![allow(clippy::derive_partial_eq_without_eq, clippy::disallowed_names)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use axum::extract::*;
|
||||
use axum_extra::extract::{CookieJar, Multipart};
|
||||
use bytes::Bytes;
|
||||
use http::Method;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use types::*;
|
||||
|
||||
pub const BASE_PATH: &str = "{{{basePathWithoutHost}}}";
|
||||
{{#appVersion}}
|
||||
pub const API_VERSION: &str = "{{{.}}}";
|
||||
{{/appVersion}}
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{>response}}
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
|
||||
/// API
|
||||
#[async_trait]
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub trait Api {
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
|
||||
{{#summary}}
|
||||
/// {{{.}}}.
|
||||
///
|
||||
{{/summary}}
|
||||
{{#vendorExtensions}}
|
||||
/// {{{operationId}}} - {{{httpMethod}}} {{{basePathWithoutHost}}}{{{path}}}
|
||||
async fn {{{x-operation-id}}}(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
{{#headerParams.size}}
|
||||
header_params: models::{{{operationIdCamelCase}}}HeaderParams,
|
||||
{{/headerParams.size}}
|
||||
{{#pathParams.size}}
|
||||
path_params: models::{{{operationIdCamelCase}}}PathParams,
|
||||
{{/pathParams.size}}
|
||||
{{#queryParams.size}}
|
||||
query_params: models::{{{operationIdCamelCase}}}QueryParams,
|
||||
{{/queryParams.size}}
|
||||
{{^x-consumes-multipart-related}}
|
||||
{{^x-consumes-multipart}}
|
||||
{{#bodyParam}}
|
||||
{{#vendorExtensions}}
|
||||
{{^x-consumes-plain-text}}
|
||||
body: {{^required}}Option<{{/required}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/x-consumes-plain-text}}
|
||||
{{#x-consumes-plain-text}}
|
||||
{{#isString}}
|
||||
body: String,
|
||||
{{/isString}}
|
||||
{{^isString}}
|
||||
body: Bytes,
|
||||
{{/isString}}
|
||||
{{/x-consumes-plain-text}}
|
||||
{{/vendorExtensions}}
|
||||
{{/bodyParam}}
|
||||
{{/x-consumes-multipart}}
|
||||
{{/x-consumes-multipart-related}}
|
||||
{{#x-consumes-multipart}}
|
||||
body: Multipart,
|
||||
{{/x-consumes-multipart}}
|
||||
{{#x-consumes-multipart-related}}
|
||||
body: axum::body::Body,
|
||||
{{/x-consumes-multipart-related}}
|
||||
) -> Result<{{{operationId}}}Response, String>;
|
||||
{{/vendorExtensions}}
|
||||
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub mod server;
|
||||
|
||||
pub mod models;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub(crate) mod header;
|
923
modules/openapi-generator/src/main/resources/rust-axum/models.mustache
vendored
Normal file
923
modules/openapi-generator/src/main/resources/rust-axum/models.mustache
vendored
Normal file
@ -0,0 +1,923 @@
|
||||
#![allow(unused_qualifications)]
|
||||
|
||||
use http::HeaderValue;
|
||||
use validator::Validate;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
use crate::header;
|
||||
use crate::{models, types::*};
|
||||
|
||||
{{! Don't "use" structs here - they can conflict with the names of models, and mean that the code won't compile }}
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
|
||||
{{#vendorExtensions}}
|
||||
{{#headerParams.size}}
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)]
|
||||
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
|
||||
pub struct {{{operationIdCamelCase}}}HeaderParams {
|
||||
{{#headerParams}}
|
||||
{{#hasValidation}}
|
||||
#[validate(
|
||||
{{#maxLength}}
|
||||
{{#minLength}}
|
||||
length(min = {{minLength}}, max = {{maxLength}}),
|
||||
{{/minLength}}
|
||||
{{^minLength}}
|
||||
length(max = {{maxLength}}),
|
||||
{{/minLength}}
|
||||
{{/maxLength}}
|
||||
{{^maxLength}}
|
||||
{{#minLength}}
|
||||
length(min = {{minLength}}),
|
||||
{{/minLength}}
|
||||
{{/maxLength}}
|
||||
{{#pattern}}
|
||||
{{^isByteArray}}
|
||||
regex = "RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}HeaderParams_{{{paramName}}}{{/lambda.uppercase}}",
|
||||
{{/isByteArray}}
|
||||
{{#isByteArray}}
|
||||
custom ="validate_byte_{{#lambda.lowercase}}{{{operationIdCamelCase}}}HeaderParams_{{{paramName}}}{{/lambda.lowercase}}"
|
||||
{{/isByteArray}}
|
||||
{{/pattern}}
|
||||
{{#maximum}}
|
||||
{{#minimum}}
|
||||
range(min = {{minimum}}, max = {{maximum}}),
|
||||
{{/minimum}}
|
||||
{{^minimum}}
|
||||
range(max = {{maximum}}),
|
||||
{{/minimum}}
|
||||
{{/maximum}}
|
||||
{{#minimum}}
|
||||
{{^maximum}}
|
||||
range(min = {{minimum}}),
|
||||
{{/maximum}}
|
||||
{{/minimum}}
|
||||
{{#maxItems}}
|
||||
{{#minItems}}
|
||||
length(min = {{minItems}}, max = {{maxItems}}),
|
||||
{{/minItems}}
|
||||
{{^minItems}}
|
||||
length(max = {{maxItems}}),
|
||||
{{/minItems}}
|
||||
{{/maxItems}}
|
||||
{{^maxItems}}
|
||||
{{#minItems}}
|
||||
length(min = {{minItems}}),
|
||||
{{/minItems}}
|
||||
{{/maxItems}}
|
||||
)]
|
||||
{{/hasValidation}}
|
||||
pub {{{paramName}}}: {{^required}}Option<{{/required}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/headerParams}}
|
||||
}
|
||||
|
||||
{{#headerParams}}
|
||||
{{#hasValidation}}
|
||||
{{#pattern}}
|
||||
{{^isByteArray}}
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}HeaderParams_{{{paramName}}}{{/lambda.uppercase}}: regex::Regex = regex::Regex::new(r"{{ pattern }}").unwrap();
|
||||
}
|
||||
{{/isByteArray}}
|
||||
{{#isByteArray}}
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}HeaderParams_{{{paramName}}}{{/lambda.uppercase}}: regex::bytes::Regex = regex::bytes::Regex::new(r"{{ pattern }}").unwrap();
|
||||
}
|
||||
fn validate_byte_{{#lambda.lowercase}}{{{operationIdCamelCase}}}HeaderParams_{{{paramName}}}{{/lambda.lowercase}}(
|
||||
b: &ByteArray
|
||||
) -> std::result::Result<(), validator::ValidationError> {
|
||||
if !RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}HeaderParams_{{{paramName}}}{{/lambda.uppercase}}.is_match(&b.0) {
|
||||
return Err(validator::ValidationError::new("Character not allowed"));
|
||||
}
|
||||
std::result::Result::Ok(())
|
||||
}
|
||||
{{/isByteArray}}
|
||||
{{/pattern}}
|
||||
{{/hasValidation}}
|
||||
{{/headerParams}}
|
||||
|
||||
{{/headerParams.size}}
|
||||
{{#pathParams.size}}
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)]
|
||||
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
|
||||
pub struct {{{operationIdCamelCase}}}PathParams {
|
||||
{{#pathParams}}
|
||||
{{#description}}
|
||||
/// {{{.}}}
|
||||
{{/description}}
|
||||
{{#isEnum}}
|
||||
/// Note: inline enums are not fully supported by openapi-generator
|
||||
{{/isEnum}}
|
||||
{{#hasValidation}}
|
||||
#[validate(
|
||||
{{#maxLength}}
|
||||
{{#minLength}}
|
||||
length(min = {{minLength}}, max = {{maxLength}}),
|
||||
{{/minLength}}
|
||||
{{^minLength}}
|
||||
length(max = {{maxLength}}),
|
||||
{{/minLength}}
|
||||
{{/maxLength}}
|
||||
{{^maxLength}}
|
||||
{{#minLength}}
|
||||
length(min = {{minLength}}),
|
||||
{{/minLength}}
|
||||
{{/maxLength}}
|
||||
{{#pattern}}
|
||||
{{^isByteArray}}
|
||||
regex = "RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}PathParams_{{{paramName}}}{{/lambda.uppercase}}",
|
||||
{{/isByteArray}}
|
||||
{{#isByteArray}}
|
||||
custom ="validate_byte_{{#lambda.lowercase}}{{{operationIdCamelCase}}}PathParams_{{{paramName}}}{{/lambda.lowercase}}"
|
||||
{{/isByteArray}}
|
||||
{{/pattern}}
|
||||
{{#maximum}}
|
||||
{{#minimum}}
|
||||
range(min = {{minimum}}, max = {{maximum}}),
|
||||
{{/minimum}}
|
||||
{{^minimum}}
|
||||
range(max = {{maximum}}),
|
||||
{{/minimum}}
|
||||
{{/maximum}}
|
||||
{{#minimum}}
|
||||
{{^maximum}}
|
||||
range(min = {{minimum}}),
|
||||
{{/maximum}}
|
||||
{{/minimum}}
|
||||
{{#maxItems}}
|
||||
{{#minItems}}
|
||||
length(min = {{minItems}}, max = {{maxItems}}),
|
||||
{{/minItems}}
|
||||
{{^minItems}}
|
||||
length(max = {{maxItems}}),
|
||||
{{/minItems}}
|
||||
{{/maxItems}}
|
||||
{{^maxItems}}
|
||||
{{#minItems}}
|
||||
length(min = {{minItems}}),
|
||||
{{/minItems}}
|
||||
{{/maxItems}}
|
||||
)]
|
||||
{{/hasValidation}}
|
||||
{{#required}}
|
||||
pub {{{paramName}}}: {{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}},
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
{{#isNullable}}
|
||||
#[serde(deserialize_with = "deserialize_optional_nullable")]
|
||||
#[serde(default = "default_optional_nullable")]
|
||||
{{/isNullable}}
|
||||
#[serde(skip_serializing_if="Option::is_none")]
|
||||
pub {{{paramName}}}: Option<{{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}>,
|
||||
{{/required}}
|
||||
{{/pathParams}}
|
||||
}
|
||||
|
||||
{{#pathParams}}
|
||||
{{#hasValidation}}
|
||||
{{#pattern}}
|
||||
{{^isByteArray}}
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}PathParams_{{{paramName}}}{{/lambda.uppercase}}: regex::Regex = regex::Regex::new(r"{{ pattern }}").unwrap();
|
||||
}
|
||||
{{/isByteArray}}
|
||||
{{#isByteArray}}
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}PathParams_{{{paramName}}}{{/lambda.uppercase}}: regex::bytes::Regex = regex::bytes::Regex::new(r"{{ pattern }}").unwrap();
|
||||
}
|
||||
fn validate_byte_{{#lambda.lowercase}}{{{operationIdCamelCase}}}PathParams_{{{paramName}}}{{/lambda.lowercase}}(
|
||||
b: &ByteArray
|
||||
) -> std::result::Result<(), validator::ValidationError> {
|
||||
if !RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}PathParams_{{{paramName}}}{{/lambda.uppercase}}.is_match(&b.0) {
|
||||
return Err(validator::ValidationError::new("Character not allowed"));
|
||||
}
|
||||
std::result::Result::Ok(())
|
||||
}
|
||||
{{/isByteArray}}
|
||||
{{/pattern}}
|
||||
{{/hasValidation}}
|
||||
{{/pathParams}}
|
||||
|
||||
{{/pathParams.size}}
|
||||
{{#queryParams.size}}
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)]
|
||||
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
|
||||
pub struct {{{operationIdCamelCase}}}QueryParams {
|
||||
{{#queryParams}}
|
||||
{{#vendorExtensions}}
|
||||
{{#description}}
|
||||
/// {{{.}}}
|
||||
{{/description}}
|
||||
{{#isEnum}}
|
||||
/// Note: inline enums are not fully supported by openapi-generator
|
||||
{{/isEnum}}
|
||||
#[serde(rename = "{{{baseName}}}")]
|
||||
{{#hasValidation}}
|
||||
#[validate(
|
||||
{{#maxLength}}
|
||||
{{#minLength}}
|
||||
length(min = {{minLength}}, max = {{maxLength}}),
|
||||
{{/minLength}}
|
||||
{{^minLength}}
|
||||
length(max = {{maxLength}}),
|
||||
{{/minLength}}
|
||||
{{/maxLength}}
|
||||
{{^maxLength}}
|
||||
{{#minLength}}
|
||||
length(min = {{minLength}}),
|
||||
{{/minLength}}
|
||||
{{/maxLength}}
|
||||
{{#pattern}}
|
||||
{{^isByteArray}}
|
||||
regex = "RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}QueryParams_{{{paramName}}}{{/lambda.uppercase}}",
|
||||
{{/isByteArray}}
|
||||
{{#isByteArray}}
|
||||
custom ="validate_byte_{{#lambda.lowercase}}{{{operationIdCamelCase}}}QueryParams_{{{paramName}}}{{/lambda.lowercase}}"
|
||||
{{/isByteArray}}
|
||||
{{/pattern}}
|
||||
{{#maximum}}
|
||||
{{#minimum}}
|
||||
range(min = {{minimum}}, max = {{maximum}}),
|
||||
{{/minimum}}
|
||||
{{^minimum}}
|
||||
range(max = {{maximum}}),
|
||||
{{/minimum}}
|
||||
{{/maximum}}
|
||||
{{#minimum}}
|
||||
{{^maximum}}
|
||||
range(min = {{minimum}}),
|
||||
{{/maximum}}
|
||||
{{/minimum}}
|
||||
{{#maxItems}}
|
||||
{{#minItems}}
|
||||
length(min = {{minItems}}, max = {{maxItems}}),
|
||||
{{/minItems}}
|
||||
{{^minItems}}
|
||||
length(max = {{maxItems}}),
|
||||
{{/minItems}}
|
||||
{{/maxItems}}
|
||||
{{^maxItems}}
|
||||
{{#minItems}}
|
||||
length(min = {{minItems}}),
|
||||
{{/minItems}}
|
||||
{{/maxItems}}
|
||||
)]
|
||||
{{/hasValidation}}
|
||||
{{#required}}
|
||||
pub {{{paramName}}}: {{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}},
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
{{#isNullable}}
|
||||
#[serde(deserialize_with = "deserialize_optional_nullable")]
|
||||
#[serde(default = "default_optional_nullable")]
|
||||
{{/isNullable}}
|
||||
#[serde(skip_serializing_if="Option::is_none")]
|
||||
pub {{{paramName}}}: Option<{{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}>,
|
||||
{{/required}}
|
||||
{{/vendorExtensions}}
|
||||
{{/queryParams}}
|
||||
}
|
||||
|
||||
{{#queryParams}}
|
||||
{{#hasValidation}}
|
||||
{{#pattern}}
|
||||
{{^isByteArray}}
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}QueryParams_{{{paramName}}}{{/lambda.uppercase}}: regex::Regex = regex::Regex::new(r"{{ pattern }}").unwrap();
|
||||
}
|
||||
{{/isByteArray}}
|
||||
{{#isByteArray}}
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}QueryParams_{{{paramName}}}{{/lambda.uppercase}}: regex::bytes::Regex = regex::bytes::Regex::new(r"{{ pattern }}").unwrap();
|
||||
}
|
||||
fn validate_byte_{{#lambda.lowercase}}{{{operationIdCamelCase}}}QueryParams_{{{paramName}}}{{/lambda.lowercase}}(
|
||||
b: &ByteArray
|
||||
) -> std::result::Result<(), validator::ValidationError> {
|
||||
if !RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}QueryParams_{{{paramName}}}{{/lambda.uppercase}}.is_match(&b.0) {
|
||||
return Err(validator::ValidationError::new("Character not allowed"));
|
||||
}
|
||||
std::result::Result::Ok(())
|
||||
}
|
||||
{{/isByteArray}}
|
||||
{{/pattern}}
|
||||
{{/hasValidation}}
|
||||
{{/queryParams}}
|
||||
{{/queryParams.size}}
|
||||
{{/vendorExtensions}}
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
|
||||
{{! Don't "use" structs here - they can conflict with the names of models, and mean that the code won't compile }}
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
|
||||
{{#description}}
|
||||
/// {{{.}}}
|
||||
{{/description}}
|
||||
{{#isEnum}}
|
||||
/// Enumeration of values.
|
||||
/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]`
|
||||
/// which helps with FFI.
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))]
|
||||
pub enum {{{classname}}} {
|
||||
{{#allowableValues}}
|
||||
{{#enumVars}}
|
||||
#[serde(rename = {{{value}}})]
|
||||
{{{name}}},
|
||||
{{/enumVars}}
|
||||
{{/allowableValues}}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for {{{classname}}} {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
{{#allowableValues}}
|
||||
{{#enumVars}}
|
||||
{{{classname}}}::{{{name}}} => write!(f, {{{value}}}),
|
||||
{{/enumVars}}
|
||||
{{/allowableValues}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for {{{classname}}} {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
match s {
|
||||
{{#allowableValues}}
|
||||
{{#enumVars}}
|
||||
{{{value}}} => std::result::Result::Ok({{{classname}}}::{{{name}}}),
|
||||
{{/enumVars}}
|
||||
{{/allowableValues}}
|
||||
_ => std::result::Result::Err(format!("Value not valid: {}", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
{{/isEnum}}
|
||||
{{^isEnum}}
|
||||
{{#dataType}}
|
||||
{{#isMap}}
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
{{/isMap}}
|
||||
{{^isMap}}
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)]
|
||||
{{/isMap}}
|
||||
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
|
||||
pub struct {{{classname}}}({{{dataType}}});
|
||||
|
||||
impl validator::Validate for {{{classname}}} {
|
||||
fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> {
|
||||
std::result::Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<{{{dataType}}}> for {{{classname}}} {
|
||||
fn from(x: {{{dataType}}}) -> Self {
|
||||
{{{classname}}}(x)
|
||||
}
|
||||
}
|
||||
{{#vendorExtensions.x-is-string}}
|
||||
|
||||
impl std::string::ToString for {{{classname}}} {
|
||||
fn to_string(&self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for {{{classname}}} {
|
||||
type Err = std::string::ParseError;
|
||||
fn from_str(x: &str) -> std::result::Result<Self, Self::Err> {
|
||||
std::result::Result::Ok({{{classname}}}(x.to_string()))
|
||||
}
|
||||
}
|
||||
{{/vendorExtensions.x-is-string}}
|
||||
|
||||
impl std::convert::From<{{{classname}}}> for {{{dataType}}} {
|
||||
fn from(x: {{{classname}}}) -> Self {
|
||||
x.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for {{{classname}}} {
|
||||
type Target = {{{dataType}}};
|
||||
fn deref(&self) -> &{{{dataType}}} {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for {{{classname}}} {
|
||||
fn deref_mut(&mut self) -> &mut {{{dataType}}} {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
{{#additionalPropertiesType}}
|
||||
/// Converts the {{{classname}}} value to the Query Parameters representation (style=form, explode=false)
|
||||
/// specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde serializer
|
||||
impl ::std::string::ToString for {{{classname}}} {
|
||||
fn to_string(&self) -> String {
|
||||
// Skipping additionalProperties in query parameter serialization
|
||||
"".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value
|
||||
/// as specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde deserializer
|
||||
impl ::std::str::FromStr for {{{classname}}} {
|
||||
type Err = &'static str;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
std::result::Result::Err("Parsing additionalProperties for {{{classname}}} is not supported")
|
||||
}
|
||||
}
|
||||
{{/additionalPropertiesType}}
|
||||
{{/dataType}}
|
||||
{{^dataType}}
|
||||
{{#arrayModelType}}
|
||||
{{! vec}}
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
|
||||
pub struct {{{classname}}}(Vec<{{{arrayModelType}}}>);
|
||||
|
||||
impl validator::Validate for {{{classname}}} {
|
||||
fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> {
|
||||
std::result::Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<{{{arrayModelType}}}>> for {{{classname}}} {
|
||||
fn from(x: Vec<{{{arrayModelType}}}>) -> Self {
|
||||
{{{classname}}}(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<{{{classname}}}> for Vec<{{{arrayModelType}}}> {
|
||||
fn from(x: {{{classname}}}) -> Self {
|
||||
x.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::FromIterator<{{{arrayModelType}}}> for {{{classname}}} {
|
||||
fn from_iter<U: IntoIterator<Item={{{arrayModelType}}}>>(u: U) -> Self {
|
||||
{{{classname}}}(Vec::<{{{arrayModelType}}}>::from_iter(u))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::IntoIterator for {{{classname}}} {
|
||||
type Item = {{{arrayModelType}}};
|
||||
type IntoIter = std::vec::IntoIter<{{{arrayModelType}}}>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::iter::IntoIterator for &'a {{{classname}}} {
|
||||
type Item = &'a {{{arrayModelType}}};
|
||||
type IntoIter = std::slice::Iter<'a, {{{arrayModelType}}}>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::iter::IntoIterator for &'a mut {{{classname}}} {
|
||||
type Item = &'a mut {{{arrayModelType}}};
|
||||
type IntoIter = std::slice::IterMut<'a, {{{arrayModelType}}}>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for {{{classname}}} {
|
||||
type Target = Vec<{{{arrayModelType}}}>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for {{{classname}}} {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the {{{classname}}} value to the Query Parameters representation (style=form, explode=false)
|
||||
/// specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde serializer
|
||||
impl std::string::ToString for {{{classname}}} {
|
||||
fn to_string(&self) -> String {
|
||||
self.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value
|
||||
/// as specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde deserializer
|
||||
impl std::str::FromStr for {{{classname}}} {
|
||||
type Err = <{{{arrayModelType}}} as std::str::FromStr>::Err;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
let mut items = vec![];
|
||||
for item in s.split(',')
|
||||
{
|
||||
items.push(item.parse()?);
|
||||
}
|
||||
std::result::Result::Ok({{{classname}}}(items))
|
||||
}
|
||||
}
|
||||
|
||||
{{/arrayModelType}}
|
||||
{{^arrayModelType}}
|
||||
{{! general struct}}
|
||||
|
||||
{{#anyOf.size}}
|
||||
/// Any of:
|
||||
{{#anyOf}}
|
||||
/// - {{{.}}}
|
||||
{{/anyOf}}
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct {{{classname}}}(Box<serde_json::value::RawValue>);
|
||||
|
||||
impl validator::Validate for {{{classname}}}
|
||||
{
|
||||
fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> {
|
||||
std::result::Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value
|
||||
/// as specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde deserializer
|
||||
impl std::str::FromStr for {{{classname}}} {
|
||||
type Err = serde_json::Error;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
serde_json::from_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for {{{classname}}} {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.get().eq(other.0.get())
|
||||
}
|
||||
}
|
||||
{{/anyOf.size}}
|
||||
|
||||
{{#oneOf.size}}
|
||||
/// One of:
|
||||
{{#oneOf}}
|
||||
/// - {{{.}}}
|
||||
{{/oneOf}}
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct {{{classname}}}(Box<serde_json::value::RawValue>);
|
||||
|
||||
impl validator::Validate for {{{classname}}}
|
||||
{
|
||||
fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> {
|
||||
std::result::Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value
|
||||
/// as specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde deserializer
|
||||
impl std::str::FromStr for {{{classname}}} {
|
||||
type Err = serde_json::Error;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
serde_json::from_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for {{{classname}}} {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.get().eq(other.0.get())
|
||||
}
|
||||
}
|
||||
{{/oneOf.size}}
|
||||
|
||||
{{^anyOf.size}}
|
||||
{{^oneOf.size}}
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)]
|
||||
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
|
||||
pub struct {{{classname}}} {
|
||||
{{#vars}}
|
||||
{{#description}}
|
||||
/// {{{.}}}
|
||||
{{/description}}
|
||||
{{#isEnum}}
|
||||
/// Note: inline enums are not fully supported by openapi-generator
|
||||
{{/isEnum}}
|
||||
#[serde(rename = "{{{baseName}}}")]
|
||||
{{#hasValidation}}
|
||||
#[validate(
|
||||
{{#maxLength}}
|
||||
{{#minLength}}
|
||||
length(min = {{minLength}}, max = {{maxLength}}),
|
||||
{{/minLength}}
|
||||
{{^minLength}}
|
||||
length(max = {{maxLength}}),
|
||||
{{/minLength}}
|
||||
{{/maxLength}}
|
||||
{{^maxLength}}
|
||||
{{#minLength}}
|
||||
length(min = {{minLength}}),
|
||||
{{/minLength}}
|
||||
{{/maxLength}}
|
||||
{{#pattern}}
|
||||
{{^isByteArray}}
|
||||
regex = "RE_{{#lambda.uppercase}}{{{classname}}}_{{{name}}}{{/lambda.uppercase}}",
|
||||
{{/isByteArray}}
|
||||
{{#isByteArray}}
|
||||
custom ="validate_byte_{{#lambda.lowercase}}{{{classname}}}_{{{name}}}{{/lambda.lowercase}}"
|
||||
{{/isByteArray}}
|
||||
{{/pattern}}
|
||||
{{#maximum}}
|
||||
{{#minimum}}
|
||||
range(min = {{minimum}}, max = {{maximum}}),
|
||||
{{/minimum}}
|
||||
{{^minimum}}
|
||||
range(max = {{maximum}}),
|
||||
{{/minimum}}
|
||||
{{/maximum}}
|
||||
{{#minimum}}
|
||||
{{^maximum}}
|
||||
range(min = {{minimum}}),
|
||||
{{/maximum}}
|
||||
{{/minimum}}
|
||||
{{#maxItems}}
|
||||
{{#minItems}}
|
||||
length(min = {{minItems}}, max = {{maxItems}}),
|
||||
{{/minItems}}
|
||||
{{^minItems}}
|
||||
length(max = {{maxItems}}),
|
||||
{{/minItems}}
|
||||
{{/maxItems}}
|
||||
{{^maxItems}}
|
||||
{{#minItems}}
|
||||
length(min = {{minItems}}),
|
||||
{{/minItems}}
|
||||
{{/maxItems}}
|
||||
)]
|
||||
{{/hasValidation}}
|
||||
{{#required}}
|
||||
pub {{{name}}}: {{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}},
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
{{#isNullable}}
|
||||
#[serde(deserialize_with = "deserialize_optional_nullable")]
|
||||
#[serde(default = "default_optional_nullable")]
|
||||
{{/isNullable}}
|
||||
#[serde(skip_serializing_if="Option::is_none")]
|
||||
pub {{{name}}}: Option<{{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}>,
|
||||
{{/required}}
|
||||
|
||||
{{/vars}}
|
||||
}
|
||||
|
||||
{{#vars}}
|
||||
{{#hasValidation}}
|
||||
{{#pattern}}
|
||||
{{^isByteArray}}
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_{{#lambda.uppercase}}{{{classname}}}_{{{name}}}{{/lambda.uppercase}}: regex::Regex = regex::Regex::new(r"{{ pattern }}").unwrap();
|
||||
}
|
||||
{{/isByteArray}}
|
||||
{{#isByteArray}}
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_{{#lambda.uppercase}}{{{classname}}}_{{{name}}}{{/lambda.uppercase}}: regex::bytes::Regex = regex::bytes::Regex::new(r"{{ pattern }}").unwrap();
|
||||
}
|
||||
fn validate_byte_{{#lambda.lowercase}}{{{classname}}}_{{{name}}}{{/lambda.lowercase}}(
|
||||
b: &ByteArray
|
||||
) -> std::result::Result<(), validator::ValidationError> {
|
||||
if !RE_{{#lambda.uppercase}}{{{classname}}}_{{{name}}}{{/lambda.uppercase}}.is_match(&b.0) {
|
||||
return Err(validator::ValidationError::new("Character not allowed"));
|
||||
}
|
||||
std::result::Result::Ok(())
|
||||
}
|
||||
{{/isByteArray}}
|
||||
{{/pattern}}
|
||||
{{/hasValidation}}
|
||||
{{/vars}}
|
||||
|
||||
impl {{{classname}}} {
|
||||
#[allow(clippy::new_without_default, clippy::too_many_arguments)]
|
||||
pub fn new({{#vars}}{{^defaultValue}}{{{name}}}: {{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}, {{/defaultValue}}{{/vars}}) -> {{{classname}}} {
|
||||
{{{classname}}} {
|
||||
{{#vars}} {{#defaultValue}}{{{name}}}: {{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}{{{name}}}{{/defaultValue}},
|
||||
{{/vars}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the {{{classname}}} value to the Query Parameters representation (style=form, explode=false)
|
||||
/// specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde serializer
|
||||
impl std::string::ToString for {{{classname}}} {
|
||||
fn to_string(&self) -> String {
|
||||
let params: Vec<Option<String>> = vec![
|
||||
{{#vars}}
|
||||
{{#isByteArray}}
|
||||
// Skipping {{baseName}} in query parameter serialization
|
||||
{{/isByteArray}}
|
||||
{{#isBinary}}
|
||||
// Skipping {{baseName}} in query parameter serialization
|
||||
{{/isBinary}}
|
||||
{{#isMap}}
|
||||
// Skipping {{baseName}} in query parameter serialization
|
||||
{{/isMap}}
|
||||
{{^isPrimitiveType}}
|
||||
// Skipping {{baseName}} in query parameter serialization
|
||||
{{/isPrimitiveType}}
|
||||
{{^isByteArray}}{{^isBinary}}{{^isMap}}{{#isPrimitiveType}}
|
||||
{{#required}}
|
||||
Some("{{{baseName}}}".to_string()),
|
||||
{{^isArray}}
|
||||
{{#isNullable}}
|
||||
Some(self.{{{name}}}.as_ref().map_or("null".to_string(), |x| x.to_string())),
|
||||
{{/isNullable}}
|
||||
{{^isNullable}}
|
||||
Some(self.{{{name}}}.to_string()),
|
||||
{{/isNullable}}
|
||||
{{/isArray}}
|
||||
{{#isArray}}
|
||||
{{#isNullable}}
|
||||
Some(self.{{{name}}}.as_ref().map_or(vec!["null".to_string()], |x| x.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","))),
|
||||
{{/isNullable}}
|
||||
{{^isNullable}}
|
||||
Some(self.{{{name}}}.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")),
|
||||
{{/isNullable}}
|
||||
{{/isArray}}
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
self.{{{name}}}.as_ref().map(|{{{name}}}| {
|
||||
[
|
||||
"{{{baseName}}}".to_string(),
|
||||
{{^isArray}}
|
||||
{{#isNullable}}
|
||||
{{{name}}}.as_ref().map_or("null".to_string(), |x| x.to_string()),
|
||||
{{/isNullable}}
|
||||
{{^isNullable}}
|
||||
{{{name}}}.to_string(),
|
||||
{{/isNullable}}
|
||||
{{/isArray}}
|
||||
{{#isArray}}
|
||||
{{#isNullable}}
|
||||
{{{name}}}.as_ref().map_or("null".to_string(), |x| x.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")),
|
||||
{{/isNullable}}
|
||||
{{^isNullable}}
|
||||
{{{name}}}.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","),
|
||||
{{/isNullable}}
|
||||
{{/isArray}}
|
||||
].join(",")
|
||||
}),
|
||||
{{/required}}
|
||||
{{/isPrimitiveType}}{{/isMap}}{{/isBinary}}{{/isByteArray}}
|
||||
{{/vars}}
|
||||
];
|
||||
|
||||
params.into_iter().flatten().collect::<Vec<_>>().join(",")
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value
|
||||
/// as specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde deserializer
|
||||
impl std::str::FromStr for {{{classname}}} {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
/// An intermediate representation of the struct to use for parsing.
|
||||
#[derive(Default)]
|
||||
#[allow(dead_code)]
|
||||
struct IntermediateRep {
|
||||
{{#vars}}
|
||||
pub {{{name}}}: Vec<{{{dataType}}}>,
|
||||
{{/vars}}
|
||||
}
|
||||
|
||||
let mut intermediate_rep = IntermediateRep::default();
|
||||
|
||||
// Parse into intermediate representation
|
||||
let mut string_iter = s.split(',');
|
||||
let mut key_result = string_iter.next();
|
||||
|
||||
while key_result.is_some() {
|
||||
let val = match string_iter.next() {
|
||||
Some(x) => x,
|
||||
None => return std::result::Result::Err("Missing value while parsing {{{classname}}}".to_string())
|
||||
};
|
||||
|
||||
if let Some(key) = key_result {
|
||||
#[allow(clippy::match_single_binding)]
|
||||
match key {
|
||||
{{#vars}}
|
||||
{{#isBinary}}
|
||||
"{{{baseName}}}" => return std::result::Result::Err("Parsing binary data in this style is not supported in {{{classname}}}".to_string()),
|
||||
{{/isBinary}}
|
||||
{{^isBinary}}
|
||||
{{#isByteArray}}
|
||||
"{{{baseName}}}" => return std::result::Result::Err("Parsing binary data in this style is not supported in {{{classname}}}".to_string()),
|
||||
{{/isByteArray}}
|
||||
{{^isByteArray}}
|
||||
{{#isContainer}}
|
||||
"{{{baseName}}}" => return std::result::Result::Err("Parsing a container in this style is not supported in {{{classname}}}".to_string()),
|
||||
{{/isContainer}}
|
||||
{{^isContainer}}
|
||||
{{#isNullable}}
|
||||
"{{{baseName}}}" => return std::result::Result::Err("Parsing a nullable type in this style is not supported in {{{classname}}}".to_string()),
|
||||
{{/isNullable}}
|
||||
{{^isNullable}}
|
||||
#[allow(clippy::redundant_clone)]
|
||||
"{{{baseName}}}" => intermediate_rep.{{{name}}}.push(<{{{dataType}}} as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?),
|
||||
{{/isNullable}}
|
||||
{{/isContainer}}
|
||||
{{/isByteArray}}
|
||||
{{/isBinary}}
|
||||
{{/vars}}
|
||||
_ => return std::result::Result::Err("Unexpected key while parsing {{{classname}}}".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next key
|
||||
key_result = string_iter.next();
|
||||
}
|
||||
|
||||
// Use the intermediate representation to return the struct
|
||||
std::result::Result::Ok({{{classname}}} {
|
||||
{{#vars}}
|
||||
{{#isNullable}}
|
||||
{{{name}}}: std::result::Result::Err("Nullable types not supported in {{{classname}}}".to_string())?,
|
||||
{{/isNullable}}
|
||||
{{^isNullable}}
|
||||
{{{name}}}: intermediate_rep.{{{name}}}.into_iter().next(){{#required}}.ok_or_else(|| "{{{baseName}}} missing in {{{classname}}}".to_string())?{{/required}},
|
||||
{{/isNullable}}
|
||||
{{/vars}}
|
||||
})
|
||||
}
|
||||
}
|
||||
{{/oneOf.size}}
|
||||
{{/anyOf.size}}
|
||||
{{/arrayModelType}}
|
||||
|
||||
{{^anyOf.size}}
|
||||
{{^oneOf.size}}
|
||||
// Methods for converting between header::IntoHeaderValue<{{{classname}}}> and HeaderValue
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
impl std::convert::TryFrom<header::IntoHeaderValue<{{{classname}}}>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: header::IntoHeaderValue<{{{classname}}}>) -> std::result::Result<Self, Self::Error> {
|
||||
let hdr_value = hdr_value.to_string();
|
||||
match HeaderValue::from_str(&hdr_value) {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(value),
|
||||
std::result::Result::Err(e) => std::result::Result::Err(
|
||||
format!("Invalid header value for {{classname}} - value: {} is invalid {}",
|
||||
hdr_value, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
impl std::convert::TryFrom<HeaderValue> for header::IntoHeaderValue<{{{classname}}}> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> std::result::Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
std::result::Result::Ok(value) => {
|
||||
match <{{{classname}}} as std::str::FromStr>::from_str(value) {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)),
|
||||
std::result::Result::Err(err) => std::result::Result::Err(
|
||||
format!("Unable to convert header value '{}' into {{classname}} - {}",
|
||||
value, err))
|
||||
}
|
||||
},
|
||||
std::result::Result::Err(e) => std::result::Result::Err(
|
||||
format!("Unable to convert header: {:?} to string: {}",
|
||||
hdr_value, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{{/oneOf.size}}
|
||||
{{/anyOf.size}}
|
||||
|
||||
{{/dataType}}
|
||||
{{/isEnum}}
|
||||
|
||||
{{/model}}
|
||||
{{/models}}
|
71
modules/openapi-generator/src/main/resources/rust-axum/response.mustache
vendored
Normal file
71
modules/openapi-generator/src/main/resources/rust-axum/response.mustache
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
{{#vendorExtensions.x-must-use-response}}
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
{{/vendorExtensions.x-must-use-response}}
|
||||
pub enum {{{operationId}}}Response {
|
||||
{{#responses}}
|
||||
{{#message}}
|
||||
/// {{{.}}}{{/message}}
|
||||
{{#vendorExtensions}}
|
||||
{{{x-response-id}}}
|
||||
{{/vendorExtensions}}
|
||||
{{^dataType}}
|
||||
{{#hasHeaders}}
|
||||
{
|
||||
{{/hasHeaders}}
|
||||
{{/dataType}}
|
||||
{{#dataType}}
|
||||
{{^hasHeaders}}
|
||||
{{#vendorExtensions}}
|
||||
{{#x-produces-plain-text}}
|
||||
(String)
|
||||
{{/x-produces-plain-text}}
|
||||
{{#x-produces-bytes}}
|
||||
(ByteArray)
|
||||
{{/x-produces-bytes}}
|
||||
{{^x-produces-plain-text}}
|
||||
{{^x-produces-bytes}}
|
||||
({{{dataType}}})
|
||||
{{/x-produces-bytes}}
|
||||
{{/x-produces-plain-text}}
|
||||
{{/vendorExtensions}}
|
||||
{{/hasHeaders}}
|
||||
{{#hasHeaders}}
|
||||
{
|
||||
{{#vendorExtensions}}
|
||||
{{#x-produces-plain-text}}
|
||||
body: String,
|
||||
{{/x-produces-plain-text}}
|
||||
{{#x-produces-bytes}}
|
||||
body: ByteArray,
|
||||
{{/x-produces-bytes}}
|
||||
{{^x-produces-plain-text}}
|
||||
{{^x-produces-bytes}}
|
||||
body: {{{dataType}}},
|
||||
{{/x-produces-bytes}}
|
||||
{{/x-produces-plain-text}}
|
||||
{{/vendorExtensions}}
|
||||
{{/hasHeaders}}
|
||||
{{/dataType}}
|
||||
{{#headers}}
|
||||
{{{name}}}:
|
||||
{{^required}}
|
||||
Option<
|
||||
{{/required}}
|
||||
{{{dataType}}}
|
||||
{{^required}}
|
||||
>
|
||||
{{/required}}
|
||||
{{^-last}}
|
||||
,
|
||||
{{/-last}}
|
||||
{{#-last}}
|
||||
}
|
||||
{{/-last}}
|
||||
{{/headers}}
|
||||
{{^-last}}
|
||||
,
|
||||
{{/-last}}
|
||||
{{/responses}}
|
||||
}
|
13
modules/openapi-generator/src/main/resources/rust-axum/server-imports.mustache
vendored
Normal file
13
modules/openapi-generator/src/main/resources/rust-axum/server-imports.mustache
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use axum::{body::Body, extract::*, response::Response, routing::*};
|
||||
use axum_extra::extract::{CookieJar, Multipart};
|
||||
use bytes::Bytes;
|
||||
use http::{header::CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue, Method, StatusCode};
|
||||
use tracing::error;
|
||||
use validator::{Validate, ValidationErrors};
|
||||
|
||||
use crate::{header, types::*};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::models;
|
16
modules/openapi-generator/src/main/resources/rust-axum/server-mod.mustache
vendored
Normal file
16
modules/openapi-generator/src/main/resources/rust-axum/server-mod.mustache
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{{>server-imports}}
|
||||
use crate::{Api{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}},
|
||||
{{{operationId}}}Response{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
|
||||
};
|
||||
|
||||
{{>server-route}}
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{>server-operation-validate}}
|
||||
{{>server-operation}}
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
221
modules/openapi-generator/src/main/resources/rust-axum/server-operation-validate.mustache
vendored
Normal file
221
modules/openapi-generator/src/main/resources/rust-axum/server-operation-validate.mustache
vendored
Normal file
@ -0,0 +1,221 @@
|
||||
{{^x-consumes-multipart-related}}
|
||||
{{^x-consumes-multipart}}
|
||||
{{#bodyParam}}
|
||||
{{#vendorExtensions}}
|
||||
#[derive(validator::Validate)]
|
||||
#[allow(dead_code)]
|
||||
struct {{{operationIdCamelCase}}}BodyValidator<'a> {
|
||||
{{#hasValidation}}
|
||||
#[validate(
|
||||
{{#maxLength}}
|
||||
{{#minLength}}
|
||||
length(min = {{minLength}}, max = {{maxLength}}),
|
||||
{{/minLength}}
|
||||
{{^minLength}}
|
||||
length(max = {{maxLength}}),
|
||||
{{/minLength}}
|
||||
{{/maxLength}}
|
||||
{{^maxLength}}
|
||||
{{#minLength}}
|
||||
length(min = {{minLength}}),
|
||||
{{/minLength}}
|
||||
{{/maxLength}}
|
||||
{{#pattern}}
|
||||
{{#isString}}
|
||||
regex = "RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}BodyValidator{{/lambda.uppercase}}",
|
||||
{{/isString}}
|
||||
{{^isString}}
|
||||
custom ="validate_byte_{{#lambda.lowercase}}{{{operationIdCamelCase}}}BodyValidator{{/lambda.lowercase}}",
|
||||
{{/isString}}
|
||||
{{/pattern}}
|
||||
{{#maximum}}
|
||||
{{#minimum}}
|
||||
range(min = {{minimum}}, max = {{maximum}}),
|
||||
{{/minimum}}
|
||||
{{^minimum}}
|
||||
range(max = {{maximum}}),
|
||||
{{/minimum}}
|
||||
{{/maximum}}
|
||||
{{#minimum}}
|
||||
{{^maximum}}
|
||||
range(min = {{minimum}}),
|
||||
{{/maximum}}
|
||||
{{/minimum}}
|
||||
{{#maxItems}}
|
||||
{{#minItems}}
|
||||
length(min = {{minItems}}, max = {{maxItems}}),
|
||||
{{/minItems}}
|
||||
{{^minItems}}
|
||||
length(max = {{maxItems}}),
|
||||
{{/minItems}}
|
||||
{{/maxItems}}
|
||||
{{^maxItems}}
|
||||
{{#minItems}}
|
||||
length(min = {{minItems}}),
|
||||
{{/minItems}}
|
||||
{{/maxItems}}
|
||||
)]
|
||||
{{/hasValidation}}
|
||||
{{^x-consumes-plain-text}}
|
||||
{{^hasValidation}}
|
||||
{{^isMap}}
|
||||
#[validate]
|
||||
{{/isMap}}
|
||||
{{/hasValidation}}
|
||||
body: &'a {{{dataType}}},
|
||||
{{/x-consumes-plain-text}}
|
||||
{{#x-consumes-plain-text}}
|
||||
{{#isString}}
|
||||
body: &'a String,
|
||||
{{/isString}}
|
||||
{{^isString}}
|
||||
body: &'a [u8],
|
||||
{{/isString}}
|
||||
{{/x-consumes-plain-text}}
|
||||
}
|
||||
|
||||
{{#hasValidation}}
|
||||
{{#pattern}}
|
||||
{{#isString}}
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}BodyValidator{{/lambda.uppercase}}: regex::Regex = regex::Regex::new(r"{{ pattern }}").unwrap();
|
||||
}
|
||||
{{/isString}}
|
||||
{{^isString}}
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}BodyValidator{{/lambda.uppercase}}: regex::bytes::Regex = regex::bytes::Regex::new(r"{{ pattern }}").unwrap();
|
||||
}
|
||||
fn validate_byte_{{#lambda.lowercase}}{{{operationIdCamelCase}}}BodyValidator{{/lambda.lowercase}}(
|
||||
b: &[u8]
|
||||
) -> std::result::Result<(), validator::ValidationError> {
|
||||
if !RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}BodyValidator{{/lambda.uppercase}}.is_match(b) {
|
||||
return Err(validator::ValidationError::new("Character not allowed"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
{{/isString}}
|
||||
{{/pattern}}
|
||||
{{/hasValidation}}
|
||||
{{/vendorExtensions}}
|
||||
{{/bodyParam}}
|
||||
{{/x-consumes-multipart}}
|
||||
{{/x-consumes-multipart-related}}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn {{#vendorExtensions}}{{{x-operation-id}}}_validation{{/vendorExtensions}}(
|
||||
{{#headerParams.size}}
|
||||
header_params: models::{{{operationIdCamelCase}}}HeaderParams,
|
||||
{{/headerParams.size}}
|
||||
{{#pathParams.size}}
|
||||
path_params: models::{{{operationIdCamelCase}}}PathParams,
|
||||
{{/pathParams.size}}
|
||||
{{#queryParams.size}}
|
||||
query_params: models::{{{operationIdCamelCase}}}QueryParams,
|
||||
{{/queryParams.size}}
|
||||
{{^x-consumes-multipart-related}}
|
||||
{{^x-consumes-multipart}}
|
||||
{{#bodyParam}}
|
||||
{{#vendorExtensions}}
|
||||
{{^x-consumes-plain-text}}
|
||||
body: {{^required}}Option<{{/required}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/x-consumes-plain-text}}
|
||||
{{#x-consumes-plain-text}}
|
||||
{{#isString}}
|
||||
body: String,
|
||||
{{/isString}}
|
||||
{{^isString}}
|
||||
body: Bytes,
|
||||
{{/isString}}
|
||||
{{/x-consumes-plain-text}}
|
||||
{{/vendorExtensions}}
|
||||
{{/bodyParam}}
|
||||
{{/x-consumes-multipart}}
|
||||
{{/x-consumes-multipart-related}}
|
||||
) -> std::result::Result<(
|
||||
{{#headerParams.size}}
|
||||
models::{{{operationIdCamelCase}}}HeaderParams,
|
||||
{{/headerParams.size}}
|
||||
{{#pathParams.size}}
|
||||
models::{{{operationIdCamelCase}}}PathParams,
|
||||
{{/pathParams.size}}
|
||||
{{#queryParams.size}}
|
||||
models::{{{operationIdCamelCase}}}QueryParams,
|
||||
{{/queryParams.size}}
|
||||
{{^x-consumes-multipart-related}}
|
||||
{{^x-consumes-multipart}}
|
||||
{{#bodyParam}}
|
||||
{{#vendorExtensions}}
|
||||
{{^x-consumes-plain-text}}
|
||||
{{^required}}Option<{{/required}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/x-consumes-plain-text}}
|
||||
{{#x-consumes-plain-text}}
|
||||
{{#isString}}
|
||||
String,
|
||||
{{/isString}}
|
||||
{{^isString}}
|
||||
Bytes,
|
||||
{{/isString}}
|
||||
{{/x-consumes-plain-text}}
|
||||
{{/vendorExtensions}}
|
||||
{{/bodyParam}}
|
||||
{{/x-consumes-multipart}}
|
||||
{{/x-consumes-multipart-related}}
|
||||
), ValidationErrors>
|
||||
{
|
||||
{{#headerParams.size}}
|
||||
header_params.validate()?;
|
||||
{{/headerParams.size}}
|
||||
{{#pathParams.size}}
|
||||
path_params.validate()?;
|
||||
{{/pathParams.size}}
|
||||
{{#queryParams.size}}
|
||||
query_params.validate()?;
|
||||
{{/queryParams.size}}
|
||||
{{^x-consumes-multipart-related}}
|
||||
{{^x-consumes-multipart}}
|
||||
{{#bodyParam}}
|
||||
{{#vendorExtensions}}
|
||||
{{^x-consumes-plain-text}}
|
||||
{{#required}}
|
||||
let b = {{{operationIdCamelCase}}}BodyValidator { body: &body };
|
||||
b.validate()?;
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
if let Some(body) = &body {
|
||||
let b = {{{operationIdCamelCase}}}BodyValidator { body };
|
||||
b.validate()?;
|
||||
}
|
||||
{{/required}}
|
||||
{{/x-consumes-plain-text}}
|
||||
{{#x-consumes-plain-text}}
|
||||
{{#hasValidation}}
|
||||
let b = {{{operationIdCamelCase}}}BodyValidator { body: &body };
|
||||
b.validate()?;
|
||||
{{/hasValidation}}
|
||||
{{/x-consumes-plain-text}}
|
||||
{{/vendorExtensions}}
|
||||
{{/bodyParam}}
|
||||
{{/x-consumes-multipart}}
|
||||
{{/x-consumes-multipart-related}}
|
||||
|
||||
Ok((
|
||||
{{#headerParams.size}}
|
||||
header_params,
|
||||
{{/headerParams.size}}
|
||||
{{#pathParams.size}}
|
||||
path_params,
|
||||
{{/pathParams.size}}
|
||||
{{#queryParams.size}}
|
||||
query_params,
|
||||
{{/queryParams.size}}
|
||||
{{^x-consumes-multipart-related}}
|
||||
{{^x-consumes-multipart}}
|
||||
{{#bodyParam}}
|
||||
{{#vendorExtensions}}
|
||||
body,
|
||||
{{/vendorExtensions}}
|
||||
{{/bodyParam}}
|
||||
{{/x-consumes-multipart}}
|
||||
{{/x-consumes-multipart-related}}
|
||||
))
|
||||
}
|
309
modules/openapi-generator/src/main/resources/rust-axum/server-operation.mustache
vendored
Normal file
309
modules/openapi-generator/src/main/resources/rust-axum/server-operation.mustache
vendored
Normal file
@ -0,0 +1,309 @@
|
||||
/// {{{operationId}}} - {{{httpMethod}}} {{{basePathWithoutHost}}}{{{path}}}
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn {{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}<I, A>(
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
{{#headerParams.size}}
|
||||
headers: HeaderMap,
|
||||
{{/headerParams.size}}
|
||||
{{#pathParams.size}}
|
||||
Path(path_params): Path<models::{{{operationIdCamelCase}}}PathParams>,
|
||||
{{/pathParams.size}}
|
||||
{{#queryParams.size}}
|
||||
Query(query_params): Query<models::{{{operationIdCamelCase}}}QueryParams>,
|
||||
{{/queryParams.size}}
|
||||
State(api_impl): State<I>,
|
||||
{{#vendorExtensions}}
|
||||
{{^x-consumes-multipart-related}}
|
||||
{{^x-consumes-multipart}}
|
||||
{{#bodyParam}}
|
||||
{{#vendorExtensions}}
|
||||
{{#x-consumes-json}}
|
||||
Json(body): Json<{{^required}}Option<{{/required}}{{{dataType}}}{{^required}}>{{/required}}>,
|
||||
{{/x-consumes-json}}
|
||||
{{#x-consumes-form-urlencoded}}
|
||||
Form(body): Form<{{^required}}Option<{{/required}}{{{dataType}}}{{^required}}>{{/required}}>,
|
||||
{{/x-consumes-form-urlencoded}}
|
||||
{{#x-consumes-plain-text}}
|
||||
{{#isString}}
|
||||
body: String,
|
||||
{{/isString}}
|
||||
{{^isString}}
|
||||
body: Bytes,
|
||||
{{/isString}}
|
||||
{{/x-consumes-plain-text}}
|
||||
{{/vendorExtensions}}
|
||||
{{/bodyParam}}
|
||||
{{/x-consumes-multipart}}
|
||||
{{/x-consumes-multipart-related}}
|
||||
{{#x-consumes-multipart}}
|
||||
body: Multipart,
|
||||
{{/x-consumes-multipart}}
|
||||
{{#x-consumes-multipart-related}}
|
||||
body: axum::body::Body,
|
||||
{{/x-consumes-multipart-related}}
|
||||
{{/vendorExtensions}}
|
||||
) -> Result<Response, StatusCode>
|
||||
where
|
||||
I: AsRef<A> + Send + Sync,
|
||||
A: Api,
|
||||
{
|
||||
{{#headerParams}}
|
||||
{{#-first}}
|
||||
// Header parameters
|
||||
let header_params = {
|
||||
{{/-first}}
|
||||
let header_{{{paramName}}} = headers.get(HeaderName::from_static("{{{nameInLowerCase}}}"));
|
||||
|
||||
let header_{{{paramName}}} = match header_{{{paramName}}} {
|
||||
Some(v) => match header::IntoHeaderValue::<{{{dataType}}}>::try_from((*v).clone()) {
|
||||
Ok(result) =>
|
||||
{{#required}}
|
||||
result.0,
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
Some(result.0),
|
||||
{{/required}}
|
||||
Err(err) => {
|
||||
return Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Invalid header {{{baseName}}} - {}", err))).map_err(|e| { error!(error = ?e); StatusCode::INTERNAL_SERVER_ERROR });
|
||||
|
||||
},
|
||||
},
|
||||
None => {
|
||||
{{#required}}
|
||||
return Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Missing required header {{{baseName}}}")).map_err(|e| { error!(error = ?e); StatusCode::INTERNAL_SERVER_ERROR });
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
None
|
||||
{{/required}}
|
||||
}
|
||||
};
|
||||
{{/headerParams}}
|
||||
{{#headerParams}}
|
||||
{{#-first}}
|
||||
|
||||
models::{{{operationIdCamelCase}}}HeaderParams {
|
||||
{{/-first}}
|
||||
{{{paramName}}}: header_{{{paramName}}},
|
||||
{{#-last}}
|
||||
}
|
||||
};
|
||||
|
||||
{{/-last}}
|
||||
{{/headerParams}}
|
||||
|
||||
{{^disableValidator}}
|
||||
{{^allowBlockingValidator}}
|
||||
#[allow(clippy::redundant_closure)]
|
||||
let validation = tokio::task::spawn_blocking(move ||
|
||||
{{/allowBlockingValidator}}
|
||||
{{#allowBlockingValidator}}
|
||||
let validation =
|
||||
{{/allowBlockingValidator}}
|
||||
{{#vendorExtensions}}{{{x-operation-id}}}_validation{{/vendorExtensions}}(
|
||||
{{#headerParams.size}}
|
||||
header_params,
|
||||
{{/headerParams.size}}
|
||||
{{#pathParams.size}}
|
||||
path_params,
|
||||
{{/pathParams.size}}
|
||||
{{#queryParams.size}}
|
||||
query_params,
|
||||
{{/queryParams.size}}
|
||||
{{^x-consumes-multipart-related}}
|
||||
{{^x-consumes-multipart}}
|
||||
{{#bodyParam}}
|
||||
body,
|
||||
{{/bodyParam}}
|
||||
{{/x-consumes-multipart}}
|
||||
{{/x-consumes-multipart-related}}
|
||||
)
|
||||
{{^allowBlockingValidator}}).await.unwrap(){{/allowBlockingValidator}};
|
||||
|
||||
let Ok((
|
||||
{{#headerParams.size}}
|
||||
header_params,
|
||||
{{/headerParams.size}}
|
||||
{{#pathParams.size}}
|
||||
path_params,
|
||||
{{/pathParams.size}}
|
||||
{{#queryParams.size}}
|
||||
query_params,
|
||||
{{/queryParams.size}}
|
||||
{{^x-consumes-multipart-related}}
|
||||
{{^x-consumes-multipart}}
|
||||
{{#bodyParam}}
|
||||
body,
|
||||
{{/bodyParam}}
|
||||
{{/x-consumes-multipart}}
|
||||
{{/x-consumes-multipart-related}}
|
||||
)) = validation else {
|
||||
return Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(validation.unwrap_err().to_string()))
|
||||
.map_err(|_| StatusCode::BAD_REQUEST);
|
||||
};
|
||||
{{/disableValidator}}
|
||||
|
||||
let result = api_impl.as_ref().{{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}(
|
||||
method,
|
||||
host,
|
||||
cookies,
|
||||
{{#headerParams.size}}
|
||||
header_params,
|
||||
{{/headerParams.size}}
|
||||
{{#pathParams.size}}
|
||||
path_params,
|
||||
{{/pathParams.size}}
|
||||
{{#queryParams.size}}
|
||||
query_params,
|
||||
{{/queryParams.size}}
|
||||
{{#vendorExtensions}}
|
||||
{{^x-consumes-multipart-related}}
|
||||
{{^x-consumes-multipart}}
|
||||
{{#bodyParams}}
|
||||
{{#-first}}
|
||||
body,
|
||||
{{/-first}}
|
||||
{{/bodyParams}}
|
||||
{{/x-consumes-multipart}}
|
||||
{{/x-consumes-multipart-related}}
|
||||
{{#x-consumes-multipart}}
|
||||
body,
|
||||
{{/x-consumes-multipart}}
|
||||
{{#x-consumes-multipart-related}}
|
||||
body,
|
||||
{{/x-consumes-multipart-related}}
|
||||
{{/vendorExtensions}}
|
||||
).await;
|
||||
|
||||
let mut response = Response::builder();
|
||||
|
||||
let resp = match result {
|
||||
Ok(rsp) => match rsp {
|
||||
{{#responses}}
|
||||
{{{operationId}}}Response::{{#vendorExtensions}}{{x-response-id}}{{/vendorExtensions}}
|
||||
{{#dataType}}
|
||||
{{^headers}}
|
||||
(body)
|
||||
{{/headers}}
|
||||
{{#headers}}
|
||||
{{#-first}}
|
||||
{
|
||||
body,
|
||||
{{/-first}}
|
||||
{{{name}}}{{^-last}},{{/-last}}
|
||||
{{#-last}}
|
||||
}
|
||||
{{/-last}}
|
||||
{{/headers}}
|
||||
{{/dataType}}
|
||||
{{^dataType}}
|
||||
{{#headers}}
|
||||
{{#-first}}
|
||||
{
|
||||
{{/-first}}
|
||||
{{{name}}}{{^-last}},{{/-last}}
|
||||
{{#-last}}
|
||||
}
|
||||
{{/-last}}
|
||||
{{/headers}}
|
||||
{{/dataType}}
|
||||
=> {
|
||||
{{#headers}}
|
||||
{{^required}}
|
||||
if let Some({{{name}}}) = {{{name}}} {
|
||||
{{/required}}
|
||||
let {{{name}}} = match header::IntoHeaderValue({{{name}}}).try_into() {
|
||||
Ok(val) => val,
|
||||
Err(e) => {
|
||||
return Response::builder()
|
||||
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
.body(Body::from(format!("An internal server error occurred handling {{name}} header - {}", e))).map_err(|e| { error!(error = ?e); StatusCode::INTERNAL_SERVER_ERROR });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
{
|
||||
let mut response_headers = response.headers_mut().unwrap();
|
||||
response_headers.insert(
|
||||
HeaderName::from_static("{{{nameInLowerCase}}}"),
|
||||
{{name}}
|
||||
);
|
||||
}
|
||||
{{^required}}
|
||||
}
|
||||
{{/required}}
|
||||
{{/headers}}
|
||||
|
||||
let mut response = response.status({{{code}}});
|
||||
{{#produces}}
|
||||
{{#-first}}
|
||||
{{#dataType}}
|
||||
{{#vendorExtensions}}
|
||||
{
|
||||
let mut response_headers = response.headers_mut().unwrap();
|
||||
response_headers.insert(
|
||||
CONTENT_TYPE,
|
||||
HeaderValue::from_str("{{{x-mime-type}}}").map_err(|e| { error!(error = ?e); StatusCode::INTERNAL_SERVER_ERROR })?);
|
||||
}
|
||||
|
||||
{{/vendorExtensions}}
|
||||
{{/dataType}}
|
||||
{{/-first}}
|
||||
{{/produces}}
|
||||
{{#dataType}}
|
||||
{{#vendorExtensions}}
|
||||
{{#x-produces-json}}
|
||||
{{^allowBlockingResponseSerialize}}
|
||||
let body_content = tokio::task::spawn_blocking(move ||
|
||||
{{/allowBlockingResponseSerialize}}
|
||||
{{#allowBlockingResponseSerialize}}
|
||||
let body_content =
|
||||
{{/allowBlockingResponseSerialize}}
|
||||
serde_json::to_vec(&body).map_err(|e| {
|
||||
error!(error = ?e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}){{^allowBlockingResponseSerialize}}).await.unwrap(){{/allowBlockingResponseSerialize}}?;
|
||||
{{/x-produces-json}}
|
||||
{{#x-produces-form-urlencoded}}
|
||||
{{^allowBlockingResponseSerialize}}
|
||||
let body_content = tokio::task::spawn_blocking(move ||
|
||||
{{/allowBlockingResponseSerialize}}
|
||||
{{#allowBlockingResponseSerialize}}
|
||||
let body_content =
|
||||
{{/allowBlockingResponseSerialize}}
|
||||
serde_urlencoded::to_string(body).map_err(|e| {
|
||||
error!(error = ?e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}){{^allowBlockingResponseSerialize}}).await.unwrap(){{/allowBlockingResponseSerialize}}?;
|
||||
{{/x-produces-form-urlencoded}}
|
||||
{{#x-produces-bytes}}
|
||||
let body_content = body.0;
|
||||
{{/x-produces-bytes}}
|
||||
{{#x-produces-plain-text}}
|
||||
let body_content = body;
|
||||
{{/x-produces-plain-text}}
|
||||
{{/vendorExtensions}}
|
||||
response.body(Body::from(body_content))
|
||||
{{/dataType}}
|
||||
{{^dataType}}
|
||||
response.body(Body::empty())
|
||||
{{/dataType}}
|
||||
},
|
||||
{{/responses}}
|
||||
},
|
||||
Err(_) => {
|
||||
// Application code returned an error. This should not happen, as the implementation should
|
||||
// return a valid response.
|
||||
response.status(500).body(Body::empty())
|
||||
},
|
||||
};
|
||||
|
||||
resp.map_err(|e| { error!(error = ?e); StatusCode::INTERNAL_SERVER_ERROR })
|
||||
}
|
15
modules/openapi-generator/src/main/resources/rust-axum/server-route.mustache
vendored
Normal file
15
modules/openapi-generator/src/main/resources/rust-axum/server-route.mustache
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/// Setup API Server.
|
||||
pub fn new<I, A>(api_impl: I) -> Router
|
||||
where
|
||||
I: AsRef<A> + Clone + Send + Sync + 'static,
|
||||
A: Api + 'static,
|
||||
{
|
||||
// build our application with a route
|
||||
Router::new()
|
||||
{{#pathMethodOps}}
|
||||
.route("{{{basePathWithoutHost}}}{{{path}}}",
|
||||
{{#methodOperations}}{{{method}}}({{{operationID}}}::<I, A>){{^-last}}.{{/-last}}{{/methodOperations}}
|
||||
)
|
||||
{{/pathMethodOps}}
|
||||
.with_state(api_impl)
|
||||
}
|
665
modules/openapi-generator/src/main/resources/rust-axum/types.mustache
vendored
Normal file
665
modules/openapi-generator/src/main/resources/rust-axum/types.mustache
vendored
Normal file
@ -0,0 +1,665 @@
|
||||
use std::{mem, str::FromStr};
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Object(serde_json::Value);
|
||||
|
||||
impl validator::Validate for Object {
|
||||
fn validate(&self) -> Result<(), validator::ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Object {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(serde_json::Value::String(s.to_owned())))
|
||||
}
|
||||
}
|
||||
|
||||
/// Serde helper function to create a default `Option<Nullable<T>>` while
|
||||
/// deserializing
|
||||
pub fn default_optional_nullable<T>() -> Option<Nullable<T>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Serde helper function to deserialize into an `Option<Nullable<T>>`
|
||||
pub fn deserialize_optional_nullable<'de, D, T>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<Nullable<T>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
Option::<T>::deserialize(deserializer).map(|val| match val {
|
||||
Some(inner) => Some(Nullable::Present(inner)),
|
||||
None => Some(Nullable::Null),
|
||||
})
|
||||
}
|
||||
|
||||
/// The Nullable type. Represents a value which may be specified as null on an API.
|
||||
/// Note that this is distinct from a value that is optional and not present!
|
||||
///
|
||||
/// Nullable implements many of the same methods as the Option type (map, unwrap, etc).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum Nullable<T> {
|
||||
/// Null value
|
||||
Null,
|
||||
/// Value is present
|
||||
Present(T),
|
||||
}
|
||||
|
||||
impl<T> Nullable<T> {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `true` if the Nullable is a `Present` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_present(), true);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_present(), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_present(&self) -> bool {
|
||||
match *self {
|
||||
Nullable::Present(_) => true,
|
||||
Nullable::Null => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the Nullable is a `Null` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_null(), false);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_null(), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_null(&self) -> bool {
|
||||
!self.is_present()
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert an `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, preserving the original.
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take a `Nullable` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: enum.Nullable.html#method.map
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let num_as_str: Nullable<String> = Nullable::Present("10".to_string());
|
||||
/// // First, cast `Nullable<String>` to `Nullable<&String>` with `as_ref`,
|
||||
/// // then consume *that* with `map`, leaving `num_as_str` on the stack.
|
||||
/// let num_as_int: Nullable<usize> = num_as_str.as_ref().map(|n| n.len());
|
||||
/// println!("still can print num_as_str: {:?}", num_as_str);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_ref(&self) -> Nullable<&T> {
|
||||
match *self {
|
||||
Nullable::Present(ref x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// match x.as_mut() {
|
||||
/// Nullable::Present(v) => *v = 42,
|
||||
/// Nullable::Null => {},
|
||||
/// }
|
||||
/// assert_eq!(x, Nullable::Present(42));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut(&mut self) -> Nullable<&mut T> {
|
||||
match *self {
|
||||
Nullable::Present(ref mut x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Getting to contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Unwraps a Nullable, yielding the content of a `Nullable::Present`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is a [`Nullable::Null`] with a custom panic message provided by
|
||||
/// `msg`.
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("value");
|
||||
/// assert_eq!(x.expect("the world is ending"), "value");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// x.expect("the world is ending"); // panics with `the world is ending`
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn expect(self, msg: &str) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => expect_failed(msg),
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves the value `v` out of the `Nullable<T>` if it is `Nullable::Present(v)`.
|
||||
///
|
||||
/// In general, because this function may panic, its use is discouraged.
|
||||
/// Instead, prefer to use pattern matching and handle the `Nullable::Null`
|
||||
/// case explicitly.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the self value equals [`Nullable::Null`].
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("air");
|
||||
/// assert_eq!(x.unwrap(), "air");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.unwrap(), "air"); // fails
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => panic!("called `Nullable::unwrap()` on a `Nullable::Null` value"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or a default.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("car").unwrap_or("bike"), "car");
|
||||
/// assert_eq!(Nullable::Null.unwrap_or("bike"), "bike");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or(self, def: T) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => def,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or computes it from a closure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let k = 10;
|
||||
/// assert_eq!(Nullable::Present(4).unwrap_or_else(|| 2 * k), 4);
|
||||
/// assert_eq!(Nullable::Null.unwrap_or_else(|| 2 * k), 20);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Transforming contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps a `Nullable<T>` to `Nullable<U>` by applying a function to a contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert a `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, consuming the original:
|
||||
///
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let maybe_some_string = Nullable::Present(String::from("Hello, World!"));
|
||||
/// // `Nullable::map` takes self *by value*, consuming `maybe_some_string`
|
||||
/// let maybe_some_len = maybe_some_string.map(|s| s.len());
|
||||
///
|
||||
/// assert_eq!(maybe_some_len, Nullable::Present(13));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => Nullable::Present(f(x)),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or returns a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or computes a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let k = 21;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err)`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or(0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or(0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err())`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err()),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Boolean operations on the values, eager and lazy
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Present("foo"));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and<U>(self, optb: Nullable<U>) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(_) => optb,
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise calls `f` with the
|
||||
/// wrapped value and returns the result.
|
||||
///
|
||||
/// Some languages call this operation flatmap.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// fn sq(x: u32) -> Nullable<u32> { Nullable::Present(x * x) }
|
||||
/// fn nope(_: u32) -> Nullable<u32> { Nullable::Null }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(sq), Nullable::Present(16));
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(nope), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Present(2).and_then(nope).and_then(sq), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Null.and_then(sq).and_then(sq), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and_then<U, F: FnOnce(T) -> Nullable<U>>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => f(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x = Nullable::Null;
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(100));
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or(self, optb: Nullable<T>) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => optb,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise calls `f` and
|
||||
/// returns the result.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// fn nobody() -> Nullable<&'static str> { Nullable::Null }
|
||||
/// fn vikings() -> Nullable<&'static str> { Nullable::Present("vikings") }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("barbarians").or_else(vikings),
|
||||
/// Nullable::Present("barbarians"));
|
||||
/// assert_eq!(Nullable::Null.or_else(vikings), Nullable::Present("vikings"));
|
||||
/// assert_eq!(Nullable::Null.or_else(nobody), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Takes the value out of the Nullable, leaving a `Nullable::Null` in its place.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
///
|
||||
/// let mut x: Nullable<u32> = Nullable::Null;
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn take(&mut self) -> Nullable<T> {
|
||||
mem::replace(self, Nullable::Null)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> Nullable<&'a T> {
|
||||
/// Maps an `Nullable<&T>` to an `Nullable<T>` by cloning the contents of the
|
||||
/// Nullable.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x = 12;
|
||||
/// let opt_x = Nullable::Present(&x);
|
||||
/// assert_eq!(opt_x, Nullable::Present(&12));
|
||||
/// let cloned = opt_x.cloned();
|
||||
/// assert_eq!(cloned, Nullable::Present(12));
|
||||
/// ```
|
||||
pub fn cloned(self) -> Nullable<T> {
|
||||
self.map(Clone::clone)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Nullable<T> {
|
||||
/// Returns the contained value or a default
|
||||
///
|
||||
/// Consumes the `self` argument then, if `Nullable::Present`, returns the contained
|
||||
/// value, otherwise if `Nullable::Null`, returns the default value for that
|
||||
/// type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use {{{externCrateName}}}::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(42);
|
||||
/// assert_eq!(42, x.unwrap_or_default());
|
||||
///
|
||||
/// let y: Nullable<i32> = Nullable::Null;
|
||||
/// assert_eq!(0, y.unwrap_or_default());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_default(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Nullable<T> {
|
||||
/// Returns None.
|
||||
#[inline]
|
||||
fn default() -> Nullable<T> {
|
||||
Nullable::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Nullable<T> {
|
||||
fn from(val: T) -> Nullable<T> {
|
||||
Nullable::Present(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Nullable<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
Nullable::Present(ref inner) => serializer.serialize_some(&inner),
|
||||
Nullable::Null => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Nullable<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Nullable<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// In order to deserialize a required, but nullable, value, we first have to check whether
|
||||
// the value is present at all. To do this, we deserialize to a serde_json::Value, which
|
||||
// fails if the value is missing, or gives serde_json::Value::Null if the value is present.
|
||||
// If that succeeds as null, we can easily return a Null.
|
||||
// If that succeeds as some value, we deserialize that value and return a Present.
|
||||
// If that errors, we return the error.
|
||||
let presence: Result<::serde_json::Value, _> =
|
||||
serde::Deserialize::deserialize(deserializer);
|
||||
match presence {
|
||||
Ok(serde_json::Value::Null) => Ok(Nullable::Null),
|
||||
Ok(some_value) => serde_json::from_value(some_value)
|
||||
.map(Nullable::Present)
|
||||
.map_err(serde::de::Error::custom),
|
||||
Err(x) => Err(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn expect_failed(msg: &str) -> ! {
|
||||
panic!("{}", msg)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
/// Base64-encoded byte array
|
||||
pub struct ByteArray(pub Vec<u8>);
|
||||
|
||||
impl Serialize for ByteArray {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&general_purpose::STANDARD.encode(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ByteArray {
|
||||
fn deserialize<D>(deserializer: D) -> Result<ByteArray, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
match general_purpose::STANDARD.decode(s) {
|
||||
Ok(bin) => Ok(ByteArray(bin)),
|
||||
_ => Err(serde::de::Error::custom("invalid base64")),
|
||||
}
|
||||
}
|
||||
}
|
2
samples/server/petstore/rust-axum/.gitignore
vendored
Normal file
2
samples/server/petstore/rust-axum/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
3
samples/server/petstore/rust-axum/Cargo.toml
Normal file
3
samples/server/petstore/rust-axum/Cargo.toml
Normal file
@ -0,0 +1,3 @@
|
||||
[workspace]
|
||||
members = ["output/*"]
|
||||
resolver = "2"
|
2
samples/server/petstore/rust-axum/output/multipart-v3/.gitignore
vendored
Normal file
2
samples/server/petstore/rust-axum/output/multipart-v3/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1,8 @@
|
||||
.gitignore
|
||||
Cargo.toml
|
||||
README.md
|
||||
src/header.rs
|
||||
src/lib.rs
|
||||
src/models.rs
|
||||
src/server/mod.rs
|
||||
src/types.rs
|
@ -0,0 +1 @@
|
||||
7.3.0-SNAPSHOT
|
@ -0,0 +1,46 @@
|
||||
[package]
|
||||
name = "multipart-v3"
|
||||
version = "1.0.7"
|
||||
authors = ["OpenAPI Generator team and contributors"]
|
||||
description = "API under test"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["server"]
|
||||
server = []
|
||||
conversion = [
|
||||
"frunk",
|
||||
"frunk_derives",
|
||||
"frunk_core",
|
||||
"frunk-enum-core",
|
||||
"frunk-enum-derive",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
axum = { version = "0.7" }
|
||||
axum-extra = { version = "0.9", features = ["cookie", "multipart"] }
|
||||
base64 = "0.21"
|
||||
bytes = "1"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
frunk = { version = "0.4", optional = true }
|
||||
frunk-enum-core = { version = "0.3", optional = true }
|
||||
frunk-enum-derive = { version = "0.3", optional = true }
|
||||
frunk_core = { version = "0.4", optional = true }
|
||||
frunk_derives = { version = "0.4", optional = true }
|
||||
http = "1"
|
||||
lazy_static = "1"
|
||||
regex = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
serde_urlencoded = "0.7"
|
||||
tokio = { version = "1", default-features = false, features = [
|
||||
"signal",
|
||||
"rt-multi-thread",
|
||||
] }
|
||||
tracing = { version = "0.1", features = ["attributes"] }
|
||||
uuid = { version = "1", features = ["serde"] }
|
||||
validator = { version = "0.16", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = "0.3"
|
@ -0,0 +1,91 @@
|
||||
# Rust API for multipart-v3
|
||||
|
||||
API under test
|
||||
|
||||
## Overview
|
||||
|
||||
This server was generated by the [openapi-generator]
|
||||
(https://openapi-generator.tech) project. By using the
|
||||
[OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
|
||||
server, you can easily generate a server stub.
|
||||
|
||||
To see how to make this your own, look here: [README]((https://openapi-generator.tech))
|
||||
|
||||
- API version: 1.0.7
|
||||
|
||||
|
||||
|
||||
|
||||
This autogenerated project defines an API crate `multipart-v3` which contains:
|
||||
* An `Api` trait defining the API in Rust.
|
||||
* Data types representing the underlying data model.
|
||||
* Axum router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
|
||||
* Request validations (path, query, body params) are included.
|
||||
|
||||
## Using the generated library
|
||||
|
||||
The generated library has a few optional features that can be activated through Cargo.
|
||||
|
||||
* `server`
|
||||
* This defaults to enabled and creates the basic skeleton of a server implementation based on Axum.
|
||||
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
|
||||
* `conversions`
|
||||
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
|
||||
|
||||
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
|
||||
|
||||
### Example
|
||||
|
||||
```rust
|
||||
struct ServerImpl {
|
||||
// database: sea_orm::DbConn,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[async_trait]
|
||||
impl multipart-v3::Api for ServerImpl {
|
||||
// API implementation goes here
|
||||
}
|
||||
|
||||
pub async fn start_server(addr: &str) {
|
||||
// initialize tracing
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// Init Axum router
|
||||
let app = multipart-v3::server::new(Arc::new(ServerImpl));
|
||||
|
||||
// Add layers to the router
|
||||
let app = app.layer(...);
|
||||
|
||||
// Run the server with graceful shutdown
|
||||
let listener = TcpListener::bind(addr).await.unwrap();
|
||||
axum::serve(listener, app)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,197 @@
|
||||
use std::{convert::TryFrom, fmt, ops::Deref};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use http::HeaderValue;
|
||||
|
||||
/// A struct to allow homogeneous conversion into a HeaderValue. We can't
|
||||
/// implement the From/Into trait on HeaderValue because we don't own
|
||||
/// either of the types.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct IntoHeaderValue<T>(pub T);
|
||||
|
||||
// Generic implementations
|
||||
|
||||
impl<T> Deref for IntoHeaderValue<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
// Derive for each TryFrom<T> in http::HeaderValue
|
||||
|
||||
macro_rules! ihv_generate {
|
||||
($t:ident) => {
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<$t> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse::<$t>() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse {} as a string: {}",
|
||||
stringify!($t),
|
||||
e
|
||||
)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse header {:?} as a string - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<$t>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<$t>) -> Result<Self, Self::Error> {
|
||||
Ok(hdr_value.0.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ihv_generate!(u64);
|
||||
ihv_generate!(i64);
|
||||
ihv_generate!(i16);
|
||||
ihv_generate!(u16);
|
||||
ihv_generate!(u32);
|
||||
ihv_generate!(usize);
|
||||
ihv_generate!(isize);
|
||||
ihv_generate!(i32);
|
||||
|
||||
// Custom derivations
|
||||
|
||||
// Vec<String>
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<Vec<String>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(
|
||||
hdr_value
|
||||
.split(',')
|
||||
.filter_map(|x| match x.trim() {
|
||||
"" => None,
|
||||
y => Some(y.to_string()),
|
||||
})
|
||||
.collect(),
|
||||
)),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse header: {:?} as a string - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<Vec<String>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<Vec<String>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.join(", ")) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} into a header - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<String> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())),
|
||||
Err(e) => Err(format!("Unable to convert header {:?} to {}", hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<String>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<String>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} from a header {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bool
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<bool> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!("Unable to parse bool from {} - {}", hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} from a header {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<bool>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<bool>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.to_string()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert: {:?} into a header: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DateTime
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<DateTime<Utc>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) {
|
||||
Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))),
|
||||
Err(e) => Err(format!("Unable to parse: {} as date - {}", hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert header {:?} to string {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<DateTime<Utc>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<DateTime<Utc>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} to a header: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
#![allow(
|
||||
missing_docs,
|
||||
trivial_casts,
|
||||
unused_variables,
|
||||
unused_mut,
|
||||
unused_imports,
|
||||
unused_extern_crates,
|
||||
non_camel_case_types
|
||||
)]
|
||||
#![allow(unused_imports, unused_attributes)]
|
||||
#![allow(clippy::derive_partial_eq_without_eq, clippy::disallowed_names)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use axum::extract::*;
|
||||
use axum_extra::extract::{CookieJar, Multipart};
|
||||
use bytes::Bytes;
|
||||
use http::Method;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use types::*;
|
||||
|
||||
pub const BASE_PATH: &str = "";
|
||||
pub const API_VERSION: &str = "1.0.7";
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MultipartRelatedRequestPostResponse {
|
||||
/// OK
|
||||
OK,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MultipartRequestPostResponse {
|
||||
/// OK
|
||||
OK,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MultipleIdenticalMimeTypesPostResponse {
|
||||
/// OK
|
||||
OK,
|
||||
}
|
||||
|
||||
/// API
|
||||
#[async_trait]
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub trait Api {
|
||||
/// MultipartRelatedRequestPost - POST /multipart_related_request
|
||||
async fn multipart_related_request_post(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: axum::body::Body,
|
||||
) -> Result<MultipartRelatedRequestPostResponse, String>;
|
||||
|
||||
/// MultipartRequestPost - POST /multipart_request
|
||||
async fn multipart_request_post(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Multipart,
|
||||
) -> Result<MultipartRequestPostResponse, String>;
|
||||
|
||||
/// MultipleIdenticalMimeTypesPost - POST /multiple-identical-mime-types
|
||||
async fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: axum::body::Body,
|
||||
) -> Result<MultipleIdenticalMimeTypesPostResponse, String>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub mod server;
|
||||
|
||||
pub mod models;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub(crate) mod header;
|
@ -0,0 +1,446 @@
|
||||
#![allow(unused_qualifications)]
|
||||
|
||||
use http::HeaderValue;
|
||||
use validator::Validate;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
use crate::header;
|
||||
use crate::{models, types::*};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)]
|
||||
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
|
||||
pub struct MultipartRelatedRequest {
|
||||
#[serde(rename = "object_field")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub object_field: Option<models::MultipartRequestObjectField>,
|
||||
|
||||
#[serde(rename = "optional_binary_field")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub optional_binary_field: Option<ByteArray>,
|
||||
|
||||
#[serde(rename = "required_binary_field")]
|
||||
pub required_binary_field: ByteArray,
|
||||
}
|
||||
|
||||
impl MultipartRelatedRequest {
|
||||
#[allow(clippy::new_without_default, clippy::too_many_arguments)]
|
||||
pub fn new(required_binary_field: ByteArray) -> MultipartRelatedRequest {
|
||||
MultipartRelatedRequest {
|
||||
object_field: None,
|
||||
optional_binary_field: None,
|
||||
required_binary_field,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the MultipartRelatedRequest value to the Query Parameters representation (style=form, explode=false)
|
||||
/// specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde serializer
|
||||
impl std::string::ToString for MultipartRelatedRequest {
|
||||
fn to_string(&self) -> String {
|
||||
let params: Vec<Option<String>> = vec![
|
||||
// Skipping object_field in query parameter serialization
|
||||
|
||||
// Skipping optional_binary_field in query parameter serialization
|
||||
// Skipping optional_binary_field in query parameter serialization
|
||||
|
||||
// Skipping required_binary_field in query parameter serialization
|
||||
// Skipping required_binary_field in query parameter serialization
|
||||
|
||||
];
|
||||
|
||||
params.into_iter().flatten().collect::<Vec<_>>().join(",")
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Query Parameters representation (style=form, explode=false) to a MultipartRelatedRequest value
|
||||
/// as specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde deserializer
|
||||
impl std::str::FromStr for MultipartRelatedRequest {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
/// An intermediate representation of the struct to use for parsing.
|
||||
#[derive(Default)]
|
||||
#[allow(dead_code)]
|
||||
struct IntermediateRep {
|
||||
pub object_field: Vec<models::MultipartRequestObjectField>,
|
||||
pub optional_binary_field: Vec<ByteArray>,
|
||||
pub required_binary_field: Vec<ByteArray>,
|
||||
}
|
||||
|
||||
let mut intermediate_rep = IntermediateRep::default();
|
||||
|
||||
// Parse into intermediate representation
|
||||
let mut string_iter = s.split(',');
|
||||
let mut key_result = string_iter.next();
|
||||
|
||||
while key_result.is_some() {
|
||||
let val = match string_iter.next() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
return std::result::Result::Err(
|
||||
"Missing value while parsing MultipartRelatedRequest".to_string(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(key) = key_result {
|
||||
#[allow(clippy::match_single_binding)]
|
||||
match key {
|
||||
#[allow(clippy::redundant_clone)]
|
||||
"object_field" => intermediate_rep.object_field.push(<models::MultipartRequestObjectField as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?),
|
||||
"optional_binary_field" => return std::result::Result::Err("Parsing binary data in this style is not supported in MultipartRelatedRequest".to_string()),
|
||||
"required_binary_field" => return std::result::Result::Err("Parsing binary data in this style is not supported in MultipartRelatedRequest".to_string()),
|
||||
_ => return std::result::Result::Err("Unexpected key while parsing MultipartRelatedRequest".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next key
|
||||
key_result = string_iter.next();
|
||||
}
|
||||
|
||||
// Use the intermediate representation to return the struct
|
||||
std::result::Result::Ok(MultipartRelatedRequest {
|
||||
object_field: intermediate_rep.object_field.into_iter().next(),
|
||||
optional_binary_field: intermediate_rep.optional_binary_field.into_iter().next(),
|
||||
required_binary_field: intermediate_rep
|
||||
.required_binary_field
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or_else(|| {
|
||||
"required_binary_field missing in MultipartRelatedRequest".to_string()
|
||||
})?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Methods for converting between header::IntoHeaderValue<MultipartRelatedRequest> and HeaderValue
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
impl std::convert::TryFrom<header::IntoHeaderValue<MultipartRelatedRequest>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(
|
||||
hdr_value: header::IntoHeaderValue<MultipartRelatedRequest>,
|
||||
) -> std::result::Result<Self, Self::Error> {
|
||||
let hdr_value = hdr_value.to_string();
|
||||
match HeaderValue::from_str(&hdr_value) {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(value),
|
||||
std::result::Result::Err(e) => std::result::Result::Err(format!(
|
||||
"Invalid header value for MultipartRelatedRequest - value: {} is invalid {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
impl std::convert::TryFrom<HeaderValue> for header::IntoHeaderValue<MultipartRelatedRequest> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> std::result::Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
std::result::Result::Ok(value) => {
|
||||
match <MultipartRelatedRequest as std::str::FromStr>::from_str(value) {
|
||||
std::result::Result::Ok(value) => {
|
||||
std::result::Result::Ok(header::IntoHeaderValue(value))
|
||||
}
|
||||
std::result::Result::Err(err) => std::result::Result::Err(format!(
|
||||
"Unable to convert header value '{}' into MultipartRelatedRequest - {}",
|
||||
value, err
|
||||
)),
|
||||
}
|
||||
}
|
||||
std::result::Result::Err(e) => std::result::Result::Err(format!(
|
||||
"Unable to convert header: {:?} to string: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)]
|
||||
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
|
||||
pub struct MultipartRequestObjectField {
|
||||
#[serde(rename = "field_a")]
|
||||
pub field_a: String,
|
||||
|
||||
#[serde(rename = "field_b")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub field_b: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl MultipartRequestObjectField {
|
||||
#[allow(clippy::new_without_default, clippy::too_many_arguments)]
|
||||
pub fn new(field_a: String) -> MultipartRequestObjectField {
|
||||
MultipartRequestObjectField {
|
||||
field_a,
|
||||
field_b: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the MultipartRequestObjectField value to the Query Parameters representation (style=form, explode=false)
|
||||
/// specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde serializer
|
||||
impl std::string::ToString for MultipartRequestObjectField {
|
||||
fn to_string(&self) -> String {
|
||||
let params: Vec<Option<String>> = vec![
|
||||
Some("field_a".to_string()),
|
||||
Some(self.field_a.to_string()),
|
||||
self.field_b.as_ref().map(|field_b| {
|
||||
[
|
||||
"field_b".to_string(),
|
||||
field_b
|
||||
.iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
]
|
||||
.join(",")
|
||||
}),
|
||||
];
|
||||
|
||||
params.into_iter().flatten().collect::<Vec<_>>().join(",")
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Query Parameters representation (style=form, explode=false) to a MultipartRequestObjectField value
|
||||
/// as specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde deserializer
|
||||
impl std::str::FromStr for MultipartRequestObjectField {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
/// An intermediate representation of the struct to use for parsing.
|
||||
#[derive(Default)]
|
||||
#[allow(dead_code)]
|
||||
struct IntermediateRep {
|
||||
pub field_a: Vec<String>,
|
||||
pub field_b: Vec<Vec<String>>,
|
||||
}
|
||||
|
||||
let mut intermediate_rep = IntermediateRep::default();
|
||||
|
||||
// Parse into intermediate representation
|
||||
let mut string_iter = s.split(',');
|
||||
let mut key_result = string_iter.next();
|
||||
|
||||
while key_result.is_some() {
|
||||
let val = match string_iter.next() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
return std::result::Result::Err(
|
||||
"Missing value while parsing MultipartRequestObjectField".to_string(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(key) = key_result {
|
||||
#[allow(clippy::match_single_binding)]
|
||||
match key {
|
||||
#[allow(clippy::redundant_clone)]
|
||||
"field_a" => intermediate_rep.field_a.push(<String as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?),
|
||||
"field_b" => return std::result::Result::Err("Parsing a container in this style is not supported in MultipartRequestObjectField".to_string()),
|
||||
_ => return std::result::Result::Err("Unexpected key while parsing MultipartRequestObjectField".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next key
|
||||
key_result = string_iter.next();
|
||||
}
|
||||
|
||||
// Use the intermediate representation to return the struct
|
||||
std::result::Result::Ok(MultipartRequestObjectField {
|
||||
field_a: intermediate_rep
|
||||
.field_a
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or_else(|| "field_a missing in MultipartRequestObjectField".to_string())?,
|
||||
field_b: intermediate_rep.field_b.into_iter().next(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Methods for converting between header::IntoHeaderValue<MultipartRequestObjectField> and HeaderValue
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
impl std::convert::TryFrom<header::IntoHeaderValue<MultipartRequestObjectField>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(
|
||||
hdr_value: header::IntoHeaderValue<MultipartRequestObjectField>,
|
||||
) -> std::result::Result<Self, Self::Error> {
|
||||
let hdr_value = hdr_value.to_string();
|
||||
match HeaderValue::from_str(&hdr_value) {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(value),
|
||||
std::result::Result::Err(e) => std::result::Result::Err(format!(
|
||||
"Invalid header value for MultipartRequestObjectField - value: {} is invalid {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
impl std::convert::TryFrom<HeaderValue> for header::IntoHeaderValue<MultipartRequestObjectField> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> std::result::Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
std::result::Result::Ok(value) => {
|
||||
match <MultipartRequestObjectField as std::str::FromStr>::from_str(value) {
|
||||
std::result::Result::Ok(value) => {
|
||||
std::result::Result::Ok(header::IntoHeaderValue(value))
|
||||
}
|
||||
std::result::Result::Err(err) => std::result::Result::Err(format!(
|
||||
"Unable to convert header value '{}' into MultipartRequestObjectField - {}",
|
||||
value, err
|
||||
)),
|
||||
}
|
||||
}
|
||||
std::result::Result::Err(e) => std::result::Result::Err(format!(
|
||||
"Unable to convert header: {:?} to string: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)]
|
||||
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
|
||||
pub struct MultipleIdenticalMimeTypesPostRequest {
|
||||
#[serde(rename = "binary1")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub binary1: Option<ByteArray>,
|
||||
|
||||
#[serde(rename = "binary2")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub binary2: Option<ByteArray>,
|
||||
}
|
||||
|
||||
impl MultipleIdenticalMimeTypesPostRequest {
|
||||
#[allow(clippy::new_without_default, clippy::too_many_arguments)]
|
||||
pub fn new() -> MultipleIdenticalMimeTypesPostRequest {
|
||||
MultipleIdenticalMimeTypesPostRequest {
|
||||
binary1: None,
|
||||
binary2: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the MultipleIdenticalMimeTypesPostRequest value to the Query Parameters representation (style=form, explode=false)
|
||||
/// specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde serializer
|
||||
impl std::string::ToString for MultipleIdenticalMimeTypesPostRequest {
|
||||
fn to_string(&self) -> String {
|
||||
let params: Vec<Option<String>> = vec![
|
||||
// Skipping binary1 in query parameter serialization
|
||||
// Skipping binary1 in query parameter serialization
|
||||
|
||||
// Skipping binary2 in query parameter serialization
|
||||
// Skipping binary2 in query parameter serialization
|
||||
|
||||
];
|
||||
|
||||
params.into_iter().flatten().collect::<Vec<_>>().join(",")
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Query Parameters representation (style=form, explode=false) to a MultipleIdenticalMimeTypesPostRequest value
|
||||
/// as specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde deserializer
|
||||
impl std::str::FromStr for MultipleIdenticalMimeTypesPostRequest {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
/// An intermediate representation of the struct to use for parsing.
|
||||
#[derive(Default)]
|
||||
#[allow(dead_code)]
|
||||
struct IntermediateRep {
|
||||
pub binary1: Vec<ByteArray>,
|
||||
pub binary2: Vec<ByteArray>,
|
||||
}
|
||||
|
||||
let mut intermediate_rep = IntermediateRep::default();
|
||||
|
||||
// Parse into intermediate representation
|
||||
let mut string_iter = s.split(',');
|
||||
let mut key_result = string_iter.next();
|
||||
|
||||
while key_result.is_some() {
|
||||
let val = match string_iter.next() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
return std::result::Result::Err(
|
||||
"Missing value while parsing MultipleIdenticalMimeTypesPostRequest"
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(key) = key_result {
|
||||
#[allow(clippy::match_single_binding)]
|
||||
match key {
|
||||
"binary1" => return std::result::Result::Err("Parsing binary data in this style is not supported in MultipleIdenticalMimeTypesPostRequest".to_string()),
|
||||
"binary2" => return std::result::Result::Err("Parsing binary data in this style is not supported in MultipleIdenticalMimeTypesPostRequest".to_string()),
|
||||
_ => return std::result::Result::Err("Unexpected key while parsing MultipleIdenticalMimeTypesPostRequest".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next key
|
||||
key_result = string_iter.next();
|
||||
}
|
||||
|
||||
// Use the intermediate representation to return the struct
|
||||
std::result::Result::Ok(MultipleIdenticalMimeTypesPostRequest {
|
||||
binary1: intermediate_rep.binary1.into_iter().next(),
|
||||
binary2: intermediate_rep.binary2.into_iter().next(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Methods for converting between header::IntoHeaderValue<MultipleIdenticalMimeTypesPostRequest> and HeaderValue
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
impl std::convert::TryFrom<header::IntoHeaderValue<MultipleIdenticalMimeTypesPostRequest>>
|
||||
for HeaderValue
|
||||
{
|
||||
type Error = String;
|
||||
|
||||
fn try_from(
|
||||
hdr_value: header::IntoHeaderValue<MultipleIdenticalMimeTypesPostRequest>,
|
||||
) -> std::result::Result<Self, Self::Error> {
|
||||
let hdr_value = hdr_value.to_string();
|
||||
match HeaderValue::from_str(&hdr_value) {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(value),
|
||||
std::result::Result::Err(e) => std::result::Result::Err(
|
||||
format!("Invalid header value for MultipleIdenticalMimeTypesPostRequest - value: {} is invalid {}",
|
||||
hdr_value, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
impl std::convert::TryFrom<HeaderValue>
|
||||
for header::IntoHeaderValue<MultipleIdenticalMimeTypesPostRequest>
|
||||
{
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> std::result::Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
std::result::Result::Ok(value) => {
|
||||
match <MultipleIdenticalMimeTypesPostRequest as std::str::FromStr>::from_str(value) {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)),
|
||||
std::result::Result::Err(err) => std::result::Result::Err(
|
||||
format!("Unable to convert header value '{}' into MultipleIdenticalMimeTypesPostRequest - {}",
|
||||
value, err))
|
||||
}
|
||||
},
|
||||
std::result::Result::Err(e) => std::result::Result::Err(
|
||||
format!("Unable to convert header: {:?} to string: {}",
|
||||
hdr_value, e))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use axum::{body::Body, extract::*, response::Response, routing::*};
|
||||
use axum_extra::extract::{CookieJar, Multipart};
|
||||
use bytes::Bytes;
|
||||
use http::{header::CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue, Method, StatusCode};
|
||||
use tracing::error;
|
||||
use validator::{Validate, ValidationErrors};
|
||||
|
||||
use crate::{header, types::*};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::models;
|
||||
|
||||
use crate::{
|
||||
Api, MultipartRelatedRequestPostResponse, MultipartRequestPostResponse,
|
||||
MultipleIdenticalMimeTypesPostResponse,
|
||||
};
|
||||
|
||||
/// Setup API Server.
|
||||
pub fn new<I, A>(api_impl: I) -> Router
|
||||
where
|
||||
I: AsRef<A> + Clone + Send + Sync + 'static,
|
||||
A: Api + 'static,
|
||||
{
|
||||
// build our application with a route
|
||||
Router::new()
|
||||
.route(
|
||||
"/multipart_related_request",
|
||||
post(multipart_related_request_post::<I, A>),
|
||||
)
|
||||
.route("/multipart_request", post(multipart_request_post::<I, A>))
|
||||
.route(
|
||||
"/multiple-identical-mime-types",
|
||||
post(multiple_identical_mime_types_post::<I, A>),
|
||||
)
|
||||
.with_state(api_impl)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn multipart_related_request_post_validation() -> std::result::Result<(), ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// MultipartRelatedRequestPost - POST /multipart_related_request
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn multipart_related_request_post<I, A>(
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
State(api_impl): State<I>,
|
||||
body: axum::body::Body,
|
||||
) -> Result<Response, StatusCode>
|
||||
where
|
||||
I: AsRef<A> + Send + Sync,
|
||||
A: Api,
|
||||
{
|
||||
#[allow(clippy::redundant_closure)]
|
||||
let validation =
|
||||
tokio::task::spawn_blocking(move || multipart_related_request_post_validation())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let Ok(()) = validation else {
|
||||
return Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(validation.unwrap_err().to_string()))
|
||||
.map_err(|_| StatusCode::BAD_REQUEST);
|
||||
};
|
||||
|
||||
let result = api_impl
|
||||
.as_ref()
|
||||
.multipart_related_request_post(method, host, cookies, body)
|
||||
.await;
|
||||
|
||||
let mut response = Response::builder();
|
||||
|
||||
let resp = match result {
|
||||
Ok(rsp) => match rsp {
|
||||
MultipartRelatedRequestPostResponse::OK => {
|
||||
let mut response = response.status(201);
|
||||
response.body(Body::empty())
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
// Application code returned an error. This should not happen, as the implementation should
|
||||
// return a valid response.
|
||||
response.status(500).body(Body::empty())
|
||||
}
|
||||
};
|
||||
|
||||
resp.map_err(|e| {
|
||||
error!(error = ?e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn multipart_request_post_validation() -> std::result::Result<(), ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// MultipartRequestPost - POST /multipart_request
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn multipart_request_post<I, A>(
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
State(api_impl): State<I>,
|
||||
body: Multipart,
|
||||
) -> Result<Response, StatusCode>
|
||||
where
|
||||
I: AsRef<A> + Send + Sync,
|
||||
A: Api,
|
||||
{
|
||||
#[allow(clippy::redundant_closure)]
|
||||
let validation = tokio::task::spawn_blocking(move || multipart_request_post_validation())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let Ok(()) = validation else {
|
||||
return Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(validation.unwrap_err().to_string()))
|
||||
.map_err(|_| StatusCode::BAD_REQUEST);
|
||||
};
|
||||
|
||||
let result = api_impl
|
||||
.as_ref()
|
||||
.multipart_request_post(method, host, cookies, body)
|
||||
.await;
|
||||
|
||||
let mut response = Response::builder();
|
||||
|
||||
let resp = match result {
|
||||
Ok(rsp) => match rsp {
|
||||
MultipartRequestPostResponse::OK => {
|
||||
let mut response = response.status(201);
|
||||
response.body(Body::empty())
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
// Application code returned an error. This should not happen, as the implementation should
|
||||
// return a valid response.
|
||||
response.status(500).body(Body::empty())
|
||||
}
|
||||
};
|
||||
|
||||
resp.map_err(|e| {
|
||||
error!(error = ?e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn multiple_identical_mime_types_post_validation() -> std::result::Result<(), ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// MultipleIdenticalMimeTypesPost - POST /multiple-identical-mime-types
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn multiple_identical_mime_types_post<I, A>(
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
State(api_impl): State<I>,
|
||||
body: axum::body::Body,
|
||||
) -> Result<Response, StatusCode>
|
||||
where
|
||||
I: AsRef<A> + Send + Sync,
|
||||
A: Api,
|
||||
{
|
||||
#[allow(clippy::redundant_closure)]
|
||||
let validation =
|
||||
tokio::task::spawn_blocking(move || multiple_identical_mime_types_post_validation())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let Ok(()) = validation else {
|
||||
return Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(validation.unwrap_err().to_string()))
|
||||
.map_err(|_| StatusCode::BAD_REQUEST);
|
||||
};
|
||||
|
||||
let result = api_impl
|
||||
.as_ref()
|
||||
.multiple_identical_mime_types_post(method, host, cookies, body)
|
||||
.await;
|
||||
|
||||
let mut response = Response::builder();
|
||||
|
||||
let resp = match result {
|
||||
Ok(rsp) => match rsp {
|
||||
MultipleIdenticalMimeTypesPostResponse::OK => {
|
||||
let mut response = response.status(200);
|
||||
response.body(Body::empty())
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
// Application code returned an error. This should not happen, as the implementation should
|
||||
// return a valid response.
|
||||
response.status(500).body(Body::empty())
|
||||
}
|
||||
};
|
||||
|
||||
resp.map_err(|e| {
|
||||
error!(error = ?e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})
|
||||
}
|
@ -0,0 +1,665 @@
|
||||
use std::{mem, str::FromStr};
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Object(serde_json::Value);
|
||||
|
||||
impl validator::Validate for Object {
|
||||
fn validate(&self) -> Result<(), validator::ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Object {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(serde_json::Value::String(s.to_owned())))
|
||||
}
|
||||
}
|
||||
|
||||
/// Serde helper function to create a default `Option<Nullable<T>>` while
|
||||
/// deserializing
|
||||
pub fn default_optional_nullable<T>() -> Option<Nullable<T>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Serde helper function to deserialize into an `Option<Nullable<T>>`
|
||||
pub fn deserialize_optional_nullable<'de, D, T>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<Nullable<T>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
Option::<T>::deserialize(deserializer).map(|val| match val {
|
||||
Some(inner) => Some(Nullable::Present(inner)),
|
||||
None => Some(Nullable::Null),
|
||||
})
|
||||
}
|
||||
|
||||
/// The Nullable type. Represents a value which may be specified as null on an API.
|
||||
/// Note that this is distinct from a value that is optional and not present!
|
||||
///
|
||||
/// Nullable implements many of the same methods as the Option type (map, unwrap, etc).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum Nullable<T> {
|
||||
/// Null value
|
||||
Null,
|
||||
/// Value is present
|
||||
Present(T),
|
||||
}
|
||||
|
||||
impl<T> Nullable<T> {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `true` if the Nullable is a `Present` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_present(), true);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_present(), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_present(&self) -> bool {
|
||||
match *self {
|
||||
Nullable::Present(_) => true,
|
||||
Nullable::Null => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the Nullable is a `Null` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_null(), false);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_null(), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_null(&self) -> bool {
|
||||
!self.is_present()
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert an `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, preserving the original.
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take a `Nullable` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: enum.Nullable.html#method.map
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let num_as_str: Nullable<String> = Nullable::Present("10".to_string());
|
||||
/// // First, cast `Nullable<String>` to `Nullable<&String>` with `as_ref`,
|
||||
/// // then consume *that* with `map`, leaving `num_as_str` on the stack.
|
||||
/// let num_as_int: Nullable<usize> = num_as_str.as_ref().map(|n| n.len());
|
||||
/// println!("still can print num_as_str: {:?}", num_as_str);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_ref(&self) -> Nullable<&T> {
|
||||
match *self {
|
||||
Nullable::Present(ref x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// match x.as_mut() {
|
||||
/// Nullable::Present(v) => *v = 42,
|
||||
/// Nullable::Null => {},
|
||||
/// }
|
||||
/// assert_eq!(x, Nullable::Present(42));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut(&mut self) -> Nullable<&mut T> {
|
||||
match *self {
|
||||
Nullable::Present(ref mut x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Getting to contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Unwraps a Nullable, yielding the content of a `Nullable::Present`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is a [`Nullable::Null`] with a custom panic message provided by
|
||||
/// `msg`.
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("value");
|
||||
/// assert_eq!(x.expect("the world is ending"), "value");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// x.expect("the world is ending"); // panics with `the world is ending`
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn expect(self, msg: &str) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => expect_failed(msg),
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves the value `v` out of the `Nullable<T>` if it is `Nullable::Present(v)`.
|
||||
///
|
||||
/// In general, because this function may panic, its use is discouraged.
|
||||
/// Instead, prefer to use pattern matching and handle the `Nullable::Null`
|
||||
/// case explicitly.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the self value equals [`Nullable::Null`].
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("air");
|
||||
/// assert_eq!(x.unwrap(), "air");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.unwrap(), "air"); // fails
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => panic!("called `Nullable::unwrap()` on a `Nullable::Null` value"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or a default.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("car").unwrap_or("bike"), "car");
|
||||
/// assert_eq!(Nullable::Null.unwrap_or("bike"), "bike");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or(self, def: T) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => def,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or computes it from a closure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let k = 10;
|
||||
/// assert_eq!(Nullable::Present(4).unwrap_or_else(|| 2 * k), 4);
|
||||
/// assert_eq!(Nullable::Null.unwrap_or_else(|| 2 * k), 20);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Transforming contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps a `Nullable<T>` to `Nullable<U>` by applying a function to a contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert a `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, consuming the original:
|
||||
///
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let maybe_some_string = Nullable::Present(String::from("Hello, World!"));
|
||||
/// // `Nullable::map` takes self *by value*, consuming `maybe_some_string`
|
||||
/// let maybe_some_len = maybe_some_string.map(|s| s.len());
|
||||
///
|
||||
/// assert_eq!(maybe_some_len, Nullable::Present(13));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => Nullable::Present(f(x)),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or returns a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or computes a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let k = 21;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err)`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or(0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or(0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err())`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err()),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Boolean operations on the values, eager and lazy
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Present("foo"));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and<U>(self, optb: Nullable<U>) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(_) => optb,
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise calls `f` with the
|
||||
/// wrapped value and returns the result.
|
||||
///
|
||||
/// Some languages call this operation flatmap.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// fn sq(x: u32) -> Nullable<u32> { Nullable::Present(x * x) }
|
||||
/// fn nope(_: u32) -> Nullable<u32> { Nullable::Null }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(sq), Nullable::Present(16));
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(nope), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Present(2).and_then(nope).and_then(sq), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Null.and_then(sq).and_then(sq), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and_then<U, F: FnOnce(T) -> Nullable<U>>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => f(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x = Nullable::Null;
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(100));
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or(self, optb: Nullable<T>) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => optb,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise calls `f` and
|
||||
/// returns the result.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// fn nobody() -> Nullable<&'static str> { Nullable::Null }
|
||||
/// fn vikings() -> Nullable<&'static str> { Nullable::Present("vikings") }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("barbarians").or_else(vikings),
|
||||
/// Nullable::Present("barbarians"));
|
||||
/// assert_eq!(Nullable::Null.or_else(vikings), Nullable::Present("vikings"));
|
||||
/// assert_eq!(Nullable::Null.or_else(nobody), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Takes the value out of the Nullable, leaving a `Nullable::Null` in its place.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
///
|
||||
/// let mut x: Nullable<u32> = Nullable::Null;
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn take(&mut self) -> Nullable<T> {
|
||||
mem::replace(self, Nullable::Null)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> Nullable<&'a T> {
|
||||
/// Maps an `Nullable<&T>` to an `Nullable<T>` by cloning the contents of the
|
||||
/// Nullable.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x = 12;
|
||||
/// let opt_x = Nullable::Present(&x);
|
||||
/// assert_eq!(opt_x, Nullable::Present(&12));
|
||||
/// let cloned = opt_x.cloned();
|
||||
/// assert_eq!(cloned, Nullable::Present(12));
|
||||
/// ```
|
||||
pub fn cloned(self) -> Nullable<T> {
|
||||
self.map(Clone::clone)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Nullable<T> {
|
||||
/// Returns the contained value or a default
|
||||
///
|
||||
/// Consumes the `self` argument then, if `Nullable::Present`, returns the contained
|
||||
/// value, otherwise if `Nullable::Null`, returns the default value for that
|
||||
/// type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use multipart_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(42);
|
||||
/// assert_eq!(42, x.unwrap_or_default());
|
||||
///
|
||||
/// let y: Nullable<i32> = Nullable::Null;
|
||||
/// assert_eq!(0, y.unwrap_or_default());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_default(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Nullable<T> {
|
||||
/// Returns None.
|
||||
#[inline]
|
||||
fn default() -> Nullable<T> {
|
||||
Nullable::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Nullable<T> {
|
||||
fn from(val: T) -> Nullable<T> {
|
||||
Nullable::Present(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Nullable<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
Nullable::Present(ref inner) => serializer.serialize_some(&inner),
|
||||
Nullable::Null => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Nullable<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Nullable<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// In order to deserialize a required, but nullable, value, we first have to check whether
|
||||
// the value is present at all. To do this, we deserialize to a serde_json::Value, which
|
||||
// fails if the value is missing, or gives serde_json::Value::Null if the value is present.
|
||||
// If that succeeds as null, we can easily return a Null.
|
||||
// If that succeeds as some value, we deserialize that value and return a Present.
|
||||
// If that errors, we return the error.
|
||||
let presence: Result<::serde_json::Value, _> =
|
||||
serde::Deserialize::deserialize(deserializer);
|
||||
match presence {
|
||||
Ok(serde_json::Value::Null) => Ok(Nullable::Null),
|
||||
Ok(some_value) => serde_json::from_value(some_value)
|
||||
.map(Nullable::Present)
|
||||
.map_err(serde::de::Error::custom),
|
||||
Err(x) => Err(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn expect_failed(msg: &str) -> ! {
|
||||
panic!("{}", msg)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
/// Base64-encoded byte array
|
||||
pub struct ByteArray(pub Vec<u8>);
|
||||
|
||||
impl Serialize for ByteArray {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&general_purpose::STANDARD.encode(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ByteArray {
|
||||
fn deserialize<D>(deserializer: D) -> Result<ByteArray, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
match general_purpose::STANDARD.decode(s) {
|
||||
Ok(bin) => Ok(ByteArray(bin)),
|
||||
_ => Err(serde::de::Error::custom("invalid base64")),
|
||||
}
|
||||
}
|
||||
}
|
2
samples/server/petstore/rust-axum/output/openapi-v3/.gitignore
vendored
Normal file
2
samples/server/petstore/rust-axum/output/openapi-v3/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1,8 @@
|
||||
.gitignore
|
||||
Cargo.toml
|
||||
README.md
|
||||
src/header.rs
|
||||
src/lib.rs
|
||||
src/models.rs
|
||||
src/server/mod.rs
|
||||
src/types.rs
|
@ -0,0 +1 @@
|
||||
7.3.0-SNAPSHOT
|
@ -0,0 +1,46 @@
|
||||
[package]
|
||||
name = "openapi-v3"
|
||||
version = "1.0.7"
|
||||
authors = ["OpenAPI Generator team and contributors"]
|
||||
description = "API under test"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["server"]
|
||||
server = []
|
||||
conversion = [
|
||||
"frunk",
|
||||
"frunk_derives",
|
||||
"frunk_core",
|
||||
"frunk-enum-core",
|
||||
"frunk-enum-derive",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
axum = { version = "0.7" }
|
||||
axum-extra = { version = "0.9", features = ["cookie", "multipart"] }
|
||||
base64 = "0.21"
|
||||
bytes = "1"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
frunk = { version = "0.4", optional = true }
|
||||
frunk-enum-core = { version = "0.3", optional = true }
|
||||
frunk-enum-derive = { version = "0.3", optional = true }
|
||||
frunk_core = { version = "0.4", optional = true }
|
||||
frunk_derives = { version = "0.4", optional = true }
|
||||
http = "1"
|
||||
lazy_static = "1"
|
||||
regex = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
serde_urlencoded = "0.7"
|
||||
tokio = { version = "1", default-features = false, features = [
|
||||
"signal",
|
||||
"rt-multi-thread",
|
||||
] }
|
||||
tracing = { version = "0.1", features = ["attributes"] }
|
||||
uuid = { version = "1", features = ["serde"] }
|
||||
validator = { version = "0.16", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = "0.3"
|
@ -0,0 +1,91 @@
|
||||
# Rust API for openapi-v3
|
||||
|
||||
API under test
|
||||
|
||||
## Overview
|
||||
|
||||
This server was generated by the [openapi-generator]
|
||||
(https://openapi-generator.tech) project. By using the
|
||||
[OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
|
||||
server, you can easily generate a server stub.
|
||||
|
||||
To see how to make this your own, look here: [README]((https://openapi-generator.tech))
|
||||
|
||||
- API version: 1.0.7
|
||||
|
||||
|
||||
|
||||
|
||||
This autogenerated project defines an API crate `openapi-v3` which contains:
|
||||
* An `Api` trait defining the API in Rust.
|
||||
* Data types representing the underlying data model.
|
||||
* Axum router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
|
||||
* Request validations (path, query, body params) are included.
|
||||
|
||||
## Using the generated library
|
||||
|
||||
The generated library has a few optional features that can be activated through Cargo.
|
||||
|
||||
* `server`
|
||||
* This defaults to enabled and creates the basic skeleton of a server implementation based on Axum.
|
||||
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
|
||||
* `conversions`
|
||||
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
|
||||
|
||||
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
|
||||
|
||||
### Example
|
||||
|
||||
```rust
|
||||
struct ServerImpl {
|
||||
// database: sea_orm::DbConn,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[async_trait]
|
||||
impl openapi-v3::Api for ServerImpl {
|
||||
// API implementation goes here
|
||||
}
|
||||
|
||||
pub async fn start_server(addr: &str) {
|
||||
// initialize tracing
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// Init Axum router
|
||||
let app = openapi-v3::server::new(Arc::new(ServerImpl));
|
||||
|
||||
// Add layers to the router
|
||||
let app = app.layer(...);
|
||||
|
||||
// Run the server with graceful shutdown
|
||||
let listener = TcpListener::bind(addr).await.unwrap();
|
||||
axum::serve(listener, app)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,197 @@
|
||||
use std::{convert::TryFrom, fmt, ops::Deref};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use http::HeaderValue;
|
||||
|
||||
/// A struct to allow homogeneous conversion into a HeaderValue. We can't
|
||||
/// implement the From/Into trait on HeaderValue because we don't own
|
||||
/// either of the types.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct IntoHeaderValue<T>(pub T);
|
||||
|
||||
// Generic implementations
|
||||
|
||||
impl<T> Deref for IntoHeaderValue<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
// Derive for each TryFrom<T> in http::HeaderValue
|
||||
|
||||
macro_rules! ihv_generate {
|
||||
($t:ident) => {
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<$t> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse::<$t>() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse {} as a string: {}",
|
||||
stringify!($t),
|
||||
e
|
||||
)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse header {:?} as a string - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<$t>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<$t>) -> Result<Self, Self::Error> {
|
||||
Ok(hdr_value.0.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ihv_generate!(u64);
|
||||
ihv_generate!(i64);
|
||||
ihv_generate!(i16);
|
||||
ihv_generate!(u16);
|
||||
ihv_generate!(u32);
|
||||
ihv_generate!(usize);
|
||||
ihv_generate!(isize);
|
||||
ihv_generate!(i32);
|
||||
|
||||
// Custom derivations
|
||||
|
||||
// Vec<String>
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<Vec<String>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(
|
||||
hdr_value
|
||||
.split(',')
|
||||
.filter_map(|x| match x.trim() {
|
||||
"" => None,
|
||||
y => Some(y.to_string()),
|
||||
})
|
||||
.collect(),
|
||||
)),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse header: {:?} as a string - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<Vec<String>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<Vec<String>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.join(", ")) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} into a header - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<String> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())),
|
||||
Err(e) => Err(format!("Unable to convert header {:?} to {}", hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<String>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<String>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} from a header {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bool
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<bool> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!("Unable to parse bool from {} - {}", hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} from a header {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<bool>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<bool>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.to_string()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert: {:?} into a header: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DateTime
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<DateTime<Utc>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) {
|
||||
Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))),
|
||||
Err(e) => Err(format!("Unable to parse: {} as date - {}", hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert header {:?} to string {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<DateTime<Utc>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<DateTime<Utc>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} to a header: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
482
samples/server/petstore/rust-axum/output/openapi-v3/src/lib.rs
Normal file
482
samples/server/petstore/rust-axum/output/openapi-v3/src/lib.rs
Normal file
@ -0,0 +1,482 @@
|
||||
#![allow(
|
||||
missing_docs,
|
||||
trivial_casts,
|
||||
unused_variables,
|
||||
unused_mut,
|
||||
unused_imports,
|
||||
unused_extern_crates,
|
||||
non_camel_case_types
|
||||
)]
|
||||
#![allow(unused_imports, unused_attributes)]
|
||||
#![allow(clippy::derive_partial_eq_without_eq, clippy::disallowed_names)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use axum::extract::*;
|
||||
use axum_extra::extract::{CookieJar, Multipart};
|
||||
use bytes::Bytes;
|
||||
use http::Method;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use types::*;
|
||||
|
||||
pub const BASE_PATH: &str = "";
|
||||
pub const API_VERSION: &str = "1.0.7";
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum AnyOfGetResponse {
|
||||
/// Success
|
||||
Success(models::AnyOfObject),
|
||||
/// AlternateSuccess
|
||||
AlternateSuccess(models::Model12345AnyOfObject),
|
||||
/// AnyOfSuccess
|
||||
AnyOfSuccess(models::AnyOfGet202Response),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CallbackWithHeaderPostResponse {
|
||||
/// OK
|
||||
OK,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ComplexQueryParamGetResponse {
|
||||
/// Success
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum EnumInPathPathParamGetResponse {
|
||||
/// Success
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum JsonComplexQueryParamGetResponse {
|
||||
/// Success
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MandatoryRequestHeaderGetResponse {
|
||||
/// Success
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MergePatchJsonGetResponse {
|
||||
/// merge-patch+json-encoded response
|
||||
Merge(models::AnotherXmlObject),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum MultigetGetResponse {
|
||||
/// JSON rsp
|
||||
JSONRsp(models::AnotherXmlObject),
|
||||
/// XML rsp
|
||||
XMLRsp(String),
|
||||
/// octet rsp
|
||||
OctetRsp(ByteArray),
|
||||
/// string rsp
|
||||
StringRsp(String),
|
||||
/// Duplicate Response long text. One.
|
||||
DuplicateResponseLongText(models::AnotherXmlObject),
|
||||
/// Duplicate Response long text. Two.
|
||||
DuplicateResponseLongText_2(models::AnotherXmlObject),
|
||||
/// Duplicate Response long text. Three.
|
||||
DuplicateResponseLongText_3(models::AnotherXmlObject),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MultipleAuthSchemeGetResponse {
|
||||
/// Check that limiting to multiple required auth schemes works
|
||||
CheckThatLimitingToMultipleRequiredAuthSchemesWorks,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum OneOfGetResponse {
|
||||
/// Success
|
||||
Success(models::OneOfGet200Response),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum OverrideServerGetResponse {
|
||||
/// Success.
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ParamgetGetResponse {
|
||||
/// JSON rsp
|
||||
JSONRsp(models::AnotherXmlObject),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ReadonlyAuthSchemeGetResponse {
|
||||
/// Check that limiting to a single required auth scheme works
|
||||
CheckThatLimitingToASingleRequiredAuthSchemeWorks,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum RegisterCallbackPostResponse {
|
||||
/// OK
|
||||
OK,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum RequiredOctetStreamPutResponse {
|
||||
/// OK
|
||||
OK,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum ResponsesWithHeadersGetResponse {
|
||||
/// Success
|
||||
Success {
|
||||
body: String,
|
||||
success_info: String,
|
||||
bool_header: Option<bool>,
|
||||
object_header: Option<models::ObjectHeader>,
|
||||
},
|
||||
/// Precondition Failed
|
||||
PreconditionFailed {
|
||||
further_info: Option<String>,
|
||||
failure_info: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum Rfc7807GetResponse {
|
||||
/// OK
|
||||
OK(models::ObjectWithArrayOfObjects),
|
||||
/// NotFound
|
||||
NotFound(models::ObjectWithArrayOfObjects),
|
||||
/// NotAcceptable
|
||||
NotAcceptable(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum UntypedPropertyGetResponse {
|
||||
/// Check that untyped properties works
|
||||
CheckThatUntypedPropertiesWorks,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum UuidGetResponse {
|
||||
/// Duplicate Response long text. One.
|
||||
DuplicateResponseLongText(uuid::Uuid),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum XmlExtraPostResponse {
|
||||
/// OK
|
||||
OK,
|
||||
/// Bad Request
|
||||
BadRequest,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum XmlOtherPostResponse {
|
||||
/// OK
|
||||
OK(String),
|
||||
/// Bad Request
|
||||
BadRequest,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum XmlOtherPutResponse {
|
||||
/// OK
|
||||
OK,
|
||||
/// Bad Request
|
||||
BadRequest,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum XmlPostResponse {
|
||||
/// OK
|
||||
OK,
|
||||
/// Bad Request
|
||||
BadRequest,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum XmlPutResponse {
|
||||
/// OK
|
||||
OK,
|
||||
/// Bad Request
|
||||
BadRequest,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CreateRepoResponse {
|
||||
/// Success
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GetRepoInfoResponse {
|
||||
/// OK
|
||||
OK(String),
|
||||
}
|
||||
|
||||
/// API
|
||||
#[async_trait]
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub trait Api {
|
||||
/// AnyOfGet - GET /any-of
|
||||
async fn any_of_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::AnyOfGetQueryParams,
|
||||
) -> Result<AnyOfGetResponse, String>;
|
||||
|
||||
/// CallbackWithHeaderPost - POST /callback-with-header
|
||||
async fn callback_with_header_post(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::CallbackWithHeaderPostQueryParams,
|
||||
) -> Result<CallbackWithHeaderPostResponse, String>;
|
||||
|
||||
/// ComplexQueryParamGet - GET /complex-query-param
|
||||
async fn complex_query_param_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::ComplexQueryParamGetQueryParams,
|
||||
) -> Result<ComplexQueryParamGetResponse, String>;
|
||||
|
||||
/// EnumInPathPathParamGet - GET /enum_in_path/{path_param}
|
||||
async fn enum_in_path_path_param_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::EnumInPathPathParamGetPathParams,
|
||||
) -> Result<EnumInPathPathParamGetResponse, String>;
|
||||
|
||||
/// JsonComplexQueryParamGet - GET /json-complex-query-param
|
||||
async fn json_complex_query_param_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::JsonComplexQueryParamGetQueryParams,
|
||||
) -> Result<JsonComplexQueryParamGetResponse, String>;
|
||||
|
||||
/// MandatoryRequestHeaderGet - GET /mandatory-request-header
|
||||
async fn mandatory_request_header_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
header_params: models::MandatoryRequestHeaderGetHeaderParams,
|
||||
) -> Result<MandatoryRequestHeaderGetResponse, String>;
|
||||
|
||||
/// MergePatchJsonGet - GET /merge-patch-json
|
||||
async fn merge_patch_json_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<MergePatchJsonGetResponse, String>;
|
||||
|
||||
/// Get some stuff..
|
||||
///
|
||||
/// MultigetGet - GET /multiget
|
||||
async fn multiget_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<MultigetGetResponse, String>;
|
||||
|
||||
/// MultipleAuthSchemeGet - GET /multiple_auth_scheme
|
||||
async fn multiple_auth_scheme_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<MultipleAuthSchemeGetResponse, String>;
|
||||
|
||||
/// OneOfGet - GET /one-of
|
||||
async fn one_of_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<OneOfGetResponse, String>;
|
||||
|
||||
/// OverrideServerGet - GET /override-server
|
||||
async fn override_server_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<OverrideServerGetResponse, String>;
|
||||
|
||||
/// Get some stuff with parameters..
|
||||
///
|
||||
/// ParamgetGet - GET /paramget
|
||||
async fn paramget_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::ParamgetGetQueryParams,
|
||||
) -> Result<ParamgetGetResponse, String>;
|
||||
|
||||
/// ReadonlyAuthSchemeGet - GET /readonly_auth_scheme
|
||||
async fn readonly_auth_scheme_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<ReadonlyAuthSchemeGetResponse, String>;
|
||||
|
||||
/// RegisterCallbackPost - POST /register-callback
|
||||
async fn register_callback_post(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::RegisterCallbackPostQueryParams,
|
||||
) -> Result<RegisterCallbackPostResponse, String>;
|
||||
|
||||
/// RequiredOctetStreamPut - PUT /required_octet_stream
|
||||
async fn required_octet_stream_put(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Bytes,
|
||||
) -> Result<RequiredOctetStreamPutResponse, String>;
|
||||
|
||||
/// ResponsesWithHeadersGet - GET /responses_with_headers
|
||||
async fn responses_with_headers_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<ResponsesWithHeadersGetResponse, String>;
|
||||
|
||||
/// Rfc7807Get - GET /rfc7807
|
||||
async fn rfc7807_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Rfc7807GetResponse, String>;
|
||||
|
||||
/// UntypedPropertyGet - GET /untyped_property
|
||||
async fn untyped_property_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Option<models::ObjectUntypedProps>,
|
||||
) -> Result<UntypedPropertyGetResponse, String>;
|
||||
|
||||
/// UuidGet - GET /uuid
|
||||
async fn uuid_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<UuidGetResponse, String>;
|
||||
|
||||
/// XmlExtraPost - POST /xml_extra
|
||||
async fn xml_extra_post(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Bytes,
|
||||
) -> Result<XmlExtraPostResponse, String>;
|
||||
|
||||
/// XmlOtherPost - POST /xml_other
|
||||
async fn xml_other_post(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Bytes,
|
||||
) -> Result<XmlOtherPostResponse, String>;
|
||||
|
||||
/// XmlOtherPut - PUT /xml_other
|
||||
async fn xml_other_put(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Bytes,
|
||||
) -> Result<XmlOtherPutResponse, String>;
|
||||
|
||||
/// Post an array.
|
||||
///
|
||||
/// XmlPost - POST /xml
|
||||
async fn xml_post(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Bytes,
|
||||
) -> Result<XmlPostResponse, String>;
|
||||
|
||||
/// XmlPut - PUT /xml
|
||||
async fn xml_put(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Bytes,
|
||||
) -> Result<XmlPutResponse, String>;
|
||||
|
||||
/// CreateRepo - POST /repos
|
||||
async fn create_repo(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::ObjectParam,
|
||||
) -> Result<CreateRepoResponse, String>;
|
||||
|
||||
/// GetRepoInfo - GET /repos/{repoId}
|
||||
async fn get_repo_info(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::GetRepoInfoPathParams,
|
||||
) -> Result<GetRepoInfoResponse, String>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub mod server;
|
||||
|
||||
pub mod models;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub(crate) mod header;
|
2878
samples/server/petstore/rust-axum/output/openapi-v3/src/models.rs
Normal file
2878
samples/server/petstore/rust-axum/output/openapi-v3/src/models.rs
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
665
samples/server/petstore/rust-axum/output/openapi-v3/src/types.rs
Normal file
665
samples/server/petstore/rust-axum/output/openapi-v3/src/types.rs
Normal file
@ -0,0 +1,665 @@
|
||||
use std::{mem, str::FromStr};
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Object(serde_json::Value);
|
||||
|
||||
impl validator::Validate for Object {
|
||||
fn validate(&self) -> Result<(), validator::ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Object {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(serde_json::Value::String(s.to_owned())))
|
||||
}
|
||||
}
|
||||
|
||||
/// Serde helper function to create a default `Option<Nullable<T>>` while
|
||||
/// deserializing
|
||||
pub fn default_optional_nullable<T>() -> Option<Nullable<T>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Serde helper function to deserialize into an `Option<Nullable<T>>`
|
||||
pub fn deserialize_optional_nullable<'de, D, T>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<Nullable<T>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
Option::<T>::deserialize(deserializer).map(|val| match val {
|
||||
Some(inner) => Some(Nullable::Present(inner)),
|
||||
None => Some(Nullable::Null),
|
||||
})
|
||||
}
|
||||
|
||||
/// The Nullable type. Represents a value which may be specified as null on an API.
|
||||
/// Note that this is distinct from a value that is optional and not present!
|
||||
///
|
||||
/// Nullable implements many of the same methods as the Option type (map, unwrap, etc).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum Nullable<T> {
|
||||
/// Null value
|
||||
Null,
|
||||
/// Value is present
|
||||
Present(T),
|
||||
}
|
||||
|
||||
impl<T> Nullable<T> {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `true` if the Nullable is a `Present` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_present(), true);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_present(), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_present(&self) -> bool {
|
||||
match *self {
|
||||
Nullable::Present(_) => true,
|
||||
Nullable::Null => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the Nullable is a `Null` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_null(), false);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_null(), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_null(&self) -> bool {
|
||||
!self.is_present()
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert an `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, preserving the original.
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take a `Nullable` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: enum.Nullable.html#method.map
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let num_as_str: Nullable<String> = Nullable::Present("10".to_string());
|
||||
/// // First, cast `Nullable<String>` to `Nullable<&String>` with `as_ref`,
|
||||
/// // then consume *that* with `map`, leaving `num_as_str` on the stack.
|
||||
/// let num_as_int: Nullable<usize> = num_as_str.as_ref().map(|n| n.len());
|
||||
/// println!("still can print num_as_str: {:?}", num_as_str);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_ref(&self) -> Nullable<&T> {
|
||||
match *self {
|
||||
Nullable::Present(ref x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// match x.as_mut() {
|
||||
/// Nullable::Present(v) => *v = 42,
|
||||
/// Nullable::Null => {},
|
||||
/// }
|
||||
/// assert_eq!(x, Nullable::Present(42));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut(&mut self) -> Nullable<&mut T> {
|
||||
match *self {
|
||||
Nullable::Present(ref mut x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Getting to contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Unwraps a Nullable, yielding the content of a `Nullable::Present`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is a [`Nullable::Null`] with a custom panic message provided by
|
||||
/// `msg`.
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("value");
|
||||
/// assert_eq!(x.expect("the world is ending"), "value");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// x.expect("the world is ending"); // panics with `the world is ending`
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn expect(self, msg: &str) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => expect_failed(msg),
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves the value `v` out of the `Nullable<T>` if it is `Nullable::Present(v)`.
|
||||
///
|
||||
/// In general, because this function may panic, its use is discouraged.
|
||||
/// Instead, prefer to use pattern matching and handle the `Nullable::Null`
|
||||
/// case explicitly.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the self value equals [`Nullable::Null`].
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("air");
|
||||
/// assert_eq!(x.unwrap(), "air");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.unwrap(), "air"); // fails
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => panic!("called `Nullable::unwrap()` on a `Nullable::Null` value"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or a default.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("car").unwrap_or("bike"), "car");
|
||||
/// assert_eq!(Nullable::Null.unwrap_or("bike"), "bike");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or(self, def: T) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => def,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or computes it from a closure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let k = 10;
|
||||
/// assert_eq!(Nullable::Present(4).unwrap_or_else(|| 2 * k), 4);
|
||||
/// assert_eq!(Nullable::Null.unwrap_or_else(|| 2 * k), 20);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Transforming contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps a `Nullable<T>` to `Nullable<U>` by applying a function to a contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert a `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, consuming the original:
|
||||
///
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let maybe_some_string = Nullable::Present(String::from("Hello, World!"));
|
||||
/// // `Nullable::map` takes self *by value*, consuming `maybe_some_string`
|
||||
/// let maybe_some_len = maybe_some_string.map(|s| s.len());
|
||||
///
|
||||
/// assert_eq!(maybe_some_len, Nullable::Present(13));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => Nullable::Present(f(x)),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or returns a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or computes a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let k = 21;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err)`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or(0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or(0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err())`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err()),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Boolean operations on the values, eager and lazy
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Present("foo"));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and<U>(self, optb: Nullable<U>) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(_) => optb,
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise calls `f` with the
|
||||
/// wrapped value and returns the result.
|
||||
///
|
||||
/// Some languages call this operation flatmap.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// fn sq(x: u32) -> Nullable<u32> { Nullable::Present(x * x) }
|
||||
/// fn nope(_: u32) -> Nullable<u32> { Nullable::Null }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(sq), Nullable::Present(16));
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(nope), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Present(2).and_then(nope).and_then(sq), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Null.and_then(sq).and_then(sq), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and_then<U, F: FnOnce(T) -> Nullable<U>>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => f(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x = Nullable::Null;
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(100));
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or(self, optb: Nullable<T>) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => optb,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise calls `f` and
|
||||
/// returns the result.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// fn nobody() -> Nullable<&'static str> { Nullable::Null }
|
||||
/// fn vikings() -> Nullable<&'static str> { Nullable::Present("vikings") }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("barbarians").or_else(vikings),
|
||||
/// Nullable::Present("barbarians"));
|
||||
/// assert_eq!(Nullable::Null.or_else(vikings), Nullable::Present("vikings"));
|
||||
/// assert_eq!(Nullable::Null.or_else(nobody), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Takes the value out of the Nullable, leaving a `Nullable::Null` in its place.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
///
|
||||
/// let mut x: Nullable<u32> = Nullable::Null;
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn take(&mut self) -> Nullable<T> {
|
||||
mem::replace(self, Nullable::Null)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> Nullable<&'a T> {
|
||||
/// Maps an `Nullable<&T>` to an `Nullable<T>` by cloning the contents of the
|
||||
/// Nullable.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x = 12;
|
||||
/// let opt_x = Nullable::Present(&x);
|
||||
/// assert_eq!(opt_x, Nullable::Present(&12));
|
||||
/// let cloned = opt_x.cloned();
|
||||
/// assert_eq!(cloned, Nullable::Present(12));
|
||||
/// ```
|
||||
pub fn cloned(self) -> Nullable<T> {
|
||||
self.map(Clone::clone)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Nullable<T> {
|
||||
/// Returns the contained value or a default
|
||||
///
|
||||
/// Consumes the `self` argument then, if `Nullable::Present`, returns the contained
|
||||
/// value, otherwise if `Nullable::Null`, returns the default value for that
|
||||
/// type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use openapi_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(42);
|
||||
/// assert_eq!(42, x.unwrap_or_default());
|
||||
///
|
||||
/// let y: Nullable<i32> = Nullable::Null;
|
||||
/// assert_eq!(0, y.unwrap_or_default());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_default(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Nullable<T> {
|
||||
/// Returns None.
|
||||
#[inline]
|
||||
fn default() -> Nullable<T> {
|
||||
Nullable::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Nullable<T> {
|
||||
fn from(val: T) -> Nullable<T> {
|
||||
Nullable::Present(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Nullable<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
Nullable::Present(ref inner) => serializer.serialize_some(&inner),
|
||||
Nullable::Null => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Nullable<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Nullable<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// In order to deserialize a required, but nullable, value, we first have to check whether
|
||||
// the value is present at all. To do this, we deserialize to a serde_json::Value, which
|
||||
// fails if the value is missing, or gives serde_json::Value::Null if the value is present.
|
||||
// If that succeeds as null, we can easily return a Null.
|
||||
// If that succeeds as some value, we deserialize that value and return a Present.
|
||||
// If that errors, we return the error.
|
||||
let presence: Result<::serde_json::Value, _> =
|
||||
serde::Deserialize::deserialize(deserializer);
|
||||
match presence {
|
||||
Ok(serde_json::Value::Null) => Ok(Nullable::Null),
|
||||
Ok(some_value) => serde_json::from_value(some_value)
|
||||
.map(Nullable::Present)
|
||||
.map_err(serde::de::Error::custom),
|
||||
Err(x) => Err(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn expect_failed(msg: &str) -> ! {
|
||||
panic!("{}", msg)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
/// Base64-encoded byte array
|
||||
pub struct ByteArray(pub Vec<u8>);
|
||||
|
||||
impl Serialize for ByteArray {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&general_purpose::STANDARD.encode(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ByteArray {
|
||||
fn deserialize<D>(deserializer: D) -> Result<ByteArray, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
match general_purpose::STANDARD.decode(s) {
|
||||
Ok(bin) => Ok(ByteArray(bin)),
|
||||
_ => Err(serde::de::Error::custom("invalid base64")),
|
||||
}
|
||||
}
|
||||
}
|
2
samples/server/petstore/rust-axum/output/ops-v3/.gitignore
vendored
Normal file
2
samples/server/petstore/rust-axum/output/ops-v3/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1,8 @@
|
||||
.gitignore
|
||||
Cargo.toml
|
||||
README.md
|
||||
src/header.rs
|
||||
src/lib.rs
|
||||
src/models.rs
|
||||
src/server/mod.rs
|
||||
src/types.rs
|
@ -0,0 +1 @@
|
||||
7.3.0-SNAPSHOT
|
46
samples/server/petstore/rust-axum/output/ops-v3/Cargo.toml
Normal file
46
samples/server/petstore/rust-axum/output/ops-v3/Cargo.toml
Normal file
@ -0,0 +1,46 @@
|
||||
[package]
|
||||
name = "ops-v3"
|
||||
version = "0.0.1"
|
||||
authors = ["OpenAPI Generator team and contributors"]
|
||||
description = "No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["server"]
|
||||
server = []
|
||||
conversion = [
|
||||
"frunk",
|
||||
"frunk_derives",
|
||||
"frunk_core",
|
||||
"frunk-enum-core",
|
||||
"frunk-enum-derive",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
axum = { version = "0.7" }
|
||||
axum-extra = { version = "0.9", features = ["cookie", "multipart"] }
|
||||
base64 = "0.21"
|
||||
bytes = "1"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
frunk = { version = "0.4", optional = true }
|
||||
frunk-enum-core = { version = "0.3", optional = true }
|
||||
frunk-enum-derive = { version = "0.3", optional = true }
|
||||
frunk_core = { version = "0.4", optional = true }
|
||||
frunk_derives = { version = "0.4", optional = true }
|
||||
http = "1"
|
||||
lazy_static = "1"
|
||||
regex = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
serde_urlencoded = "0.7"
|
||||
tokio = { version = "1", default-features = false, features = [
|
||||
"signal",
|
||||
"rt-multi-thread",
|
||||
] }
|
||||
tracing = { version = "0.1", features = ["attributes"] }
|
||||
uuid = { version = "1", features = ["serde"] }
|
||||
validator = { version = "0.16", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = "0.3"
|
91
samples/server/petstore/rust-axum/output/ops-v3/README.md
Normal file
91
samples/server/petstore/rust-axum/output/ops-v3/README.md
Normal file
@ -0,0 +1,91 @@
|
||||
# Rust API for ops-v3
|
||||
|
||||
No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
|
||||
## Overview
|
||||
|
||||
This server was generated by the [openapi-generator]
|
||||
(https://openapi-generator.tech) project. By using the
|
||||
[OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
|
||||
server, you can easily generate a server stub.
|
||||
|
||||
To see how to make this your own, look here: [README]((https://openapi-generator.tech))
|
||||
|
||||
- API version: 0.0.1
|
||||
|
||||
|
||||
|
||||
|
||||
This autogenerated project defines an API crate `ops-v3` which contains:
|
||||
* An `Api` trait defining the API in Rust.
|
||||
* Data types representing the underlying data model.
|
||||
* Axum router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
|
||||
* Request validations (path, query, body params) are included.
|
||||
|
||||
## Using the generated library
|
||||
|
||||
The generated library has a few optional features that can be activated through Cargo.
|
||||
|
||||
* `server`
|
||||
* This defaults to enabled and creates the basic skeleton of a server implementation based on Axum.
|
||||
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
|
||||
* `conversions`
|
||||
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
|
||||
|
||||
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
|
||||
|
||||
### Example
|
||||
|
||||
```rust
|
||||
struct ServerImpl {
|
||||
// database: sea_orm::DbConn,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[async_trait]
|
||||
impl ops-v3::Api for ServerImpl {
|
||||
// API implementation goes here
|
||||
}
|
||||
|
||||
pub async fn start_server(addr: &str) {
|
||||
// initialize tracing
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// Init Axum router
|
||||
let app = ops-v3::server::new(Arc::new(ServerImpl));
|
||||
|
||||
// Add layers to the router
|
||||
let app = app.layer(...);
|
||||
|
||||
// Run the server with graceful shutdown
|
||||
let listener = TcpListener::bind(addr).await.unwrap();
|
||||
axum::serve(listener, app)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
}
|
||||
```
|
180
samples/server/petstore/rust-axum/output/ops-v3/src/header.rs
Normal file
180
samples/server/petstore/rust-axum/output/ops-v3/src/header.rs
Normal file
@ -0,0 +1,180 @@
|
||||
use std::{convert::TryFrom, fmt, ops::Deref};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use http::HeaderValue;
|
||||
|
||||
/// A struct to allow homogeneous conversion into a HeaderValue. We can't
|
||||
/// implement the From/Into trait on HeaderValue because we don't own
|
||||
/// either of the types.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct IntoHeaderValue<T>(pub T);
|
||||
|
||||
// Generic implementations
|
||||
|
||||
impl<T> Deref for IntoHeaderValue<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
// Derive for each TryFrom<T> in http::HeaderValue
|
||||
|
||||
macro_rules! ihv_generate {
|
||||
($t:ident) => {
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<$t> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse::<$t>() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!("Unable to parse {} as a string: {}",
|
||||
stringify!($t), e)),
|
||||
},
|
||||
Err(e) => Err(format!("Unable to parse header {:?} as a string - {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<$t>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<$t>) -> Result<Self, Self::Error> {
|
||||
Ok(hdr_value.0.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ihv_generate!(u64);
|
||||
ihv_generate!(i64);
|
||||
ihv_generate!(i16);
|
||||
ihv_generate!(u16);
|
||||
ihv_generate!(u32);
|
||||
ihv_generate!(usize);
|
||||
ihv_generate!(isize);
|
||||
ihv_generate!(i32);
|
||||
|
||||
// Custom derivations
|
||||
|
||||
// Vec<String>
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<Vec<String>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(
|
||||
hdr_value
|
||||
.split(',')
|
||||
.filter_map(|x| match x.trim() {
|
||||
"" => None,
|
||||
y => Some(y.to_string()),
|
||||
})
|
||||
.collect())),
|
||||
Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<Vec<String>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<Vec<String>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.join(", ")) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!("Unable to convert {:?} into a header - {}",
|
||||
hdr_value, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<String> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())),
|
||||
Err(e) => Err(format!("Unable to convert header {:?} to {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<String>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<String>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!("Unable to convert {:?} from a header {}",
|
||||
hdr_value, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bool
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<bool> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!("Unable to parse bool from {} - {}",
|
||||
hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!("Unable to convert {:?} from a header {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<bool>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<bool>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.to_string()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!("Unable to convert: {:?} into a header: {}",
|
||||
hdr_value, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DateTime
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<DateTime<Utc>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) {
|
||||
Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))),
|
||||
Err(e) => Err(format!("Unable to parse: {} as date - {}",
|
||||
hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!("Unable to convert header {:?} to string {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<DateTime<Utc>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<DateTime<Utc>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!("Unable to convert {:?} to a header: {}",
|
||||
hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
586
samples/server/petstore/rust-axum/output/ops-v3/src/lib.rs
Normal file
586
samples/server/petstore/rust-axum/output/ops-v3/src/lib.rs
Normal file
@ -0,0 +1,586 @@
|
||||
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
|
||||
#![allow(unused_imports, unused_attributes)]
|
||||
#![allow(clippy::derive_partial_eq_without_eq, clippy::disallowed_names)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use axum::extract::*;
|
||||
use axum_extra::extract::{CookieJar, Multipart};
|
||||
use bytes::Bytes;
|
||||
use http::Method;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use types::*;
|
||||
|
||||
pub const BASE_PATH: &str = "";
|
||||
pub const API_VERSION: &str = "0.0.1";
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op10GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op11GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op12GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op13GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op14GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op15GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op16GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op17GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op18GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op19GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op1GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op20GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op21GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op22GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op23GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op24GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op25GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op26GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op27GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op28GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op29GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op2GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op30GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op31GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op32GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op33GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op34GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op35GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op36GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op37GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op3GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op4GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op5GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op6GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op7GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op8GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Op9GetResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
|
||||
/// API
|
||||
#[async_trait]
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub trait Api {
|
||||
|
||||
/// Op10Get - GET /op10
|
||||
async fn op10_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op10GetResponse, String>;
|
||||
|
||||
|
||||
/// Op11Get - GET /op11
|
||||
async fn op11_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op11GetResponse, String>;
|
||||
|
||||
|
||||
/// Op12Get - GET /op12
|
||||
async fn op12_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op12GetResponse, String>;
|
||||
|
||||
|
||||
/// Op13Get - GET /op13
|
||||
async fn op13_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op13GetResponse, String>;
|
||||
|
||||
|
||||
/// Op14Get - GET /op14
|
||||
async fn op14_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op14GetResponse, String>;
|
||||
|
||||
|
||||
/// Op15Get - GET /op15
|
||||
async fn op15_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op15GetResponse, String>;
|
||||
|
||||
|
||||
/// Op16Get - GET /op16
|
||||
async fn op16_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op16GetResponse, String>;
|
||||
|
||||
|
||||
/// Op17Get - GET /op17
|
||||
async fn op17_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op17GetResponse, String>;
|
||||
|
||||
|
||||
/// Op18Get - GET /op18
|
||||
async fn op18_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op18GetResponse, String>;
|
||||
|
||||
|
||||
/// Op19Get - GET /op19
|
||||
async fn op19_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op19GetResponse, String>;
|
||||
|
||||
|
||||
/// Op1Get - GET /op1
|
||||
async fn op1_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op1GetResponse, String>;
|
||||
|
||||
|
||||
/// Op20Get - GET /op20
|
||||
async fn op20_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op20GetResponse, String>;
|
||||
|
||||
|
||||
/// Op21Get - GET /op21
|
||||
async fn op21_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op21GetResponse, String>;
|
||||
|
||||
|
||||
/// Op22Get - GET /op22
|
||||
async fn op22_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op22GetResponse, String>;
|
||||
|
||||
|
||||
/// Op23Get - GET /op23
|
||||
async fn op23_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op23GetResponse, String>;
|
||||
|
||||
|
||||
/// Op24Get - GET /op24
|
||||
async fn op24_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op24GetResponse, String>;
|
||||
|
||||
|
||||
/// Op25Get - GET /op25
|
||||
async fn op25_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op25GetResponse, String>;
|
||||
|
||||
|
||||
/// Op26Get - GET /op26
|
||||
async fn op26_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op26GetResponse, String>;
|
||||
|
||||
|
||||
/// Op27Get - GET /op27
|
||||
async fn op27_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op27GetResponse, String>;
|
||||
|
||||
|
||||
/// Op28Get - GET /op28
|
||||
async fn op28_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op28GetResponse, String>;
|
||||
|
||||
|
||||
/// Op29Get - GET /op29
|
||||
async fn op29_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op29GetResponse, String>;
|
||||
|
||||
|
||||
/// Op2Get - GET /op2
|
||||
async fn op2_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op2GetResponse, String>;
|
||||
|
||||
|
||||
/// Op30Get - GET /op30
|
||||
async fn op30_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op30GetResponse, String>;
|
||||
|
||||
|
||||
/// Op31Get - GET /op31
|
||||
async fn op31_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op31GetResponse, String>;
|
||||
|
||||
|
||||
/// Op32Get - GET /op32
|
||||
async fn op32_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op32GetResponse, String>;
|
||||
|
||||
|
||||
/// Op33Get - GET /op33
|
||||
async fn op33_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op33GetResponse, String>;
|
||||
|
||||
|
||||
/// Op34Get - GET /op34
|
||||
async fn op34_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op34GetResponse, String>;
|
||||
|
||||
|
||||
/// Op35Get - GET /op35
|
||||
async fn op35_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op35GetResponse, String>;
|
||||
|
||||
|
||||
/// Op36Get - GET /op36
|
||||
async fn op36_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op36GetResponse, String>;
|
||||
|
||||
|
||||
/// Op37Get - GET /op37
|
||||
async fn op37_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op37GetResponse, String>;
|
||||
|
||||
|
||||
/// Op3Get - GET /op3
|
||||
async fn op3_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op3GetResponse, String>;
|
||||
|
||||
|
||||
/// Op4Get - GET /op4
|
||||
async fn op4_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op4GetResponse, String>;
|
||||
|
||||
|
||||
/// Op5Get - GET /op5
|
||||
async fn op5_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op5GetResponse, String>;
|
||||
|
||||
|
||||
/// Op6Get - GET /op6
|
||||
async fn op6_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op6GetResponse, String>;
|
||||
|
||||
|
||||
/// Op7Get - GET /op7
|
||||
async fn op7_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op7GetResponse, String>;
|
||||
|
||||
|
||||
/// Op8Get - GET /op8
|
||||
async fn op8_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op8GetResponse, String>;
|
||||
|
||||
|
||||
/// Op9Get - GET /op9
|
||||
async fn op9_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Op9GetResponse, String>;
|
||||
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub mod server;
|
||||
|
||||
pub mod models;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub(crate) mod header;
|
@ -0,0 +1,47 @@
|
||||
#![allow(unused_qualifications)]
|
||||
|
||||
use http::HeaderValue;
|
||||
use validator::Validate;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
use crate::header;
|
||||
use crate::{models, types::*};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
2581
samples/server/petstore/rust-axum/output/ops-v3/src/server/mod.rs
Normal file
2581
samples/server/petstore/rust-axum/output/ops-v3/src/server/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
665
samples/server/petstore/rust-axum/output/ops-v3/src/types.rs
Normal file
665
samples/server/petstore/rust-axum/output/ops-v3/src/types.rs
Normal file
@ -0,0 +1,665 @@
|
||||
use std::{mem, str::FromStr};
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Object(serde_json::Value);
|
||||
|
||||
impl validator::Validate for Object {
|
||||
fn validate(&self) -> Result<(), validator::ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Object {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(serde_json::Value::String(s.to_owned())))
|
||||
}
|
||||
}
|
||||
|
||||
/// Serde helper function to create a default `Option<Nullable<T>>` while
|
||||
/// deserializing
|
||||
pub fn default_optional_nullable<T>() -> Option<Nullable<T>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Serde helper function to deserialize into an `Option<Nullable<T>>`
|
||||
pub fn deserialize_optional_nullable<'de, D, T>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<Nullable<T>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
Option::<T>::deserialize(deserializer).map(|val| match val {
|
||||
Some(inner) => Some(Nullable::Present(inner)),
|
||||
None => Some(Nullable::Null),
|
||||
})
|
||||
}
|
||||
|
||||
/// The Nullable type. Represents a value which may be specified as null on an API.
|
||||
/// Note that this is distinct from a value that is optional and not present!
|
||||
///
|
||||
/// Nullable implements many of the same methods as the Option type (map, unwrap, etc).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum Nullable<T> {
|
||||
/// Null value
|
||||
Null,
|
||||
/// Value is present
|
||||
Present(T),
|
||||
}
|
||||
|
||||
impl<T> Nullable<T> {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `true` if the Nullable is a `Present` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_present(), true);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_present(), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_present(&self) -> bool {
|
||||
match *self {
|
||||
Nullable::Present(_) => true,
|
||||
Nullable::Null => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the Nullable is a `Null` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_null(), false);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_null(), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_null(&self) -> bool {
|
||||
!self.is_present()
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert an `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, preserving the original.
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take a `Nullable` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: enum.Nullable.html#method.map
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let num_as_str: Nullable<String> = Nullable::Present("10".to_string());
|
||||
/// // First, cast `Nullable<String>` to `Nullable<&String>` with `as_ref`,
|
||||
/// // then consume *that* with `map`, leaving `num_as_str` on the stack.
|
||||
/// let num_as_int: Nullable<usize> = num_as_str.as_ref().map(|n| n.len());
|
||||
/// println!("still can print num_as_str: {:?}", num_as_str);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_ref(&self) -> Nullable<&T> {
|
||||
match *self {
|
||||
Nullable::Present(ref x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// match x.as_mut() {
|
||||
/// Nullable::Present(v) => *v = 42,
|
||||
/// Nullable::Null => {},
|
||||
/// }
|
||||
/// assert_eq!(x, Nullable::Present(42));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut(&mut self) -> Nullable<&mut T> {
|
||||
match *self {
|
||||
Nullable::Present(ref mut x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Getting to contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Unwraps a Nullable, yielding the content of a `Nullable::Present`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is a [`Nullable::Null`] with a custom panic message provided by
|
||||
/// `msg`.
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("value");
|
||||
/// assert_eq!(x.expect("the world is ending"), "value");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// x.expect("the world is ending"); // panics with `the world is ending`
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn expect(self, msg: &str) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => expect_failed(msg),
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves the value `v` out of the `Nullable<T>` if it is `Nullable::Present(v)`.
|
||||
///
|
||||
/// In general, because this function may panic, its use is discouraged.
|
||||
/// Instead, prefer to use pattern matching and handle the `Nullable::Null`
|
||||
/// case explicitly.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the self value equals [`Nullable::Null`].
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("air");
|
||||
/// assert_eq!(x.unwrap(), "air");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.unwrap(), "air"); // fails
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => panic!("called `Nullable::unwrap()` on a `Nullable::Null` value"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or a default.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("car").unwrap_or("bike"), "car");
|
||||
/// assert_eq!(Nullable::Null.unwrap_or("bike"), "bike");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or(self, def: T) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => def,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or computes it from a closure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let k = 10;
|
||||
/// assert_eq!(Nullable::Present(4).unwrap_or_else(|| 2 * k), 4);
|
||||
/// assert_eq!(Nullable::Null.unwrap_or_else(|| 2 * k), 20);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Transforming contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps a `Nullable<T>` to `Nullable<U>` by applying a function to a contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert a `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, consuming the original:
|
||||
///
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let maybe_some_string = Nullable::Present(String::from("Hello, World!"));
|
||||
/// // `Nullable::map` takes self *by value*, consuming `maybe_some_string`
|
||||
/// let maybe_some_len = maybe_some_string.map(|s| s.len());
|
||||
///
|
||||
/// assert_eq!(maybe_some_len, Nullable::Present(13));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => Nullable::Present(f(x)),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or returns a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or computes a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let k = 21;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err)`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or(0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or(0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err())`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err()),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Boolean operations on the values, eager and lazy
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Present("foo"));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and<U>(self, optb: Nullable<U>) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(_) => optb,
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise calls `f` with the
|
||||
/// wrapped value and returns the result.
|
||||
///
|
||||
/// Some languages call this operation flatmap.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// fn sq(x: u32) -> Nullable<u32> { Nullable::Present(x * x) }
|
||||
/// fn nope(_: u32) -> Nullable<u32> { Nullable::Null }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(sq), Nullable::Present(16));
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(nope), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Present(2).and_then(nope).and_then(sq), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Null.and_then(sq).and_then(sq), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and_then<U, F: FnOnce(T) -> Nullable<U>>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => f(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x = Nullable::Null;
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(100));
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or(self, optb: Nullable<T>) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => optb,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise calls `f` and
|
||||
/// returns the result.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// fn nobody() -> Nullable<&'static str> { Nullable::Null }
|
||||
/// fn vikings() -> Nullable<&'static str> { Nullable::Present("vikings") }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("barbarians").or_else(vikings),
|
||||
/// Nullable::Present("barbarians"));
|
||||
/// assert_eq!(Nullable::Null.or_else(vikings), Nullable::Present("vikings"));
|
||||
/// assert_eq!(Nullable::Null.or_else(nobody), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Takes the value out of the Nullable, leaving a `Nullable::Null` in its place.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
///
|
||||
/// let mut x: Nullable<u32> = Nullable::Null;
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn take(&mut self) -> Nullable<T> {
|
||||
mem::replace(self, Nullable::Null)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> Nullable<&'a T> {
|
||||
/// Maps an `Nullable<&T>` to an `Nullable<T>` by cloning the contents of the
|
||||
/// Nullable.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x = 12;
|
||||
/// let opt_x = Nullable::Present(&x);
|
||||
/// assert_eq!(opt_x, Nullable::Present(&12));
|
||||
/// let cloned = opt_x.cloned();
|
||||
/// assert_eq!(cloned, Nullable::Present(12));
|
||||
/// ```
|
||||
pub fn cloned(self) -> Nullable<T> {
|
||||
self.map(Clone::clone)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Nullable<T> {
|
||||
/// Returns the contained value or a default
|
||||
///
|
||||
/// Consumes the `self` argument then, if `Nullable::Present`, returns the contained
|
||||
/// value, otherwise if `Nullable::Null`, returns the default value for that
|
||||
/// type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ops_v3::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(42);
|
||||
/// assert_eq!(42, x.unwrap_or_default());
|
||||
///
|
||||
/// let y: Nullable<i32> = Nullable::Null;
|
||||
/// assert_eq!(0, y.unwrap_or_default());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_default(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Nullable<T> {
|
||||
/// Returns None.
|
||||
#[inline]
|
||||
fn default() -> Nullable<T> {
|
||||
Nullable::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Nullable<T> {
|
||||
fn from(val: T) -> Nullable<T> {
|
||||
Nullable::Present(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Nullable<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
Nullable::Present(ref inner) => serializer.serialize_some(&inner),
|
||||
Nullable::Null => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Nullable<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Nullable<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// In order to deserialize a required, but nullable, value, we first have to check whether
|
||||
// the value is present at all. To do this, we deserialize to a serde_json::Value, which
|
||||
// fails if the value is missing, or gives serde_json::Value::Null if the value is present.
|
||||
// If that succeeds as null, we can easily return a Null.
|
||||
// If that succeeds as some value, we deserialize that value and return a Present.
|
||||
// If that errors, we return the error.
|
||||
let presence: Result<::serde_json::Value, _> =
|
||||
serde::Deserialize::deserialize(deserializer);
|
||||
match presence {
|
||||
Ok(serde_json::Value::Null) => Ok(Nullable::Null),
|
||||
Ok(some_value) => serde_json::from_value(some_value)
|
||||
.map(Nullable::Present)
|
||||
.map_err(serde::de::Error::custom),
|
||||
Err(x) => Err(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn expect_failed(msg: &str) -> ! {
|
||||
panic!("{}", msg)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
/// Base64-encoded byte array
|
||||
pub struct ByteArray(pub Vec<u8>);
|
||||
|
||||
impl Serialize for ByteArray {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&general_purpose::STANDARD.encode(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ByteArray {
|
||||
fn deserialize<D>(deserializer: D) -> Result<ByteArray, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
match general_purpose::STANDARD.decode(s) {
|
||||
Ok(bin) => Ok(ByteArray(bin)),
|
||||
_ => Err(serde::de::Error::custom("invalid base64")),
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1,8 @@
|
||||
.gitignore
|
||||
Cargo.toml
|
||||
README.md
|
||||
src/header.rs
|
||||
src/lib.rs
|
||||
src/models.rs
|
||||
src/server/mod.rs
|
||||
src/types.rs
|
@ -0,0 +1 @@
|
||||
7.3.0-SNAPSHOT
|
@ -0,0 +1,48 @@
|
||||
[package]
|
||||
name = "petstore-with-fake-endpoints-models-for-testing"
|
||||
version = "1.0.0"
|
||||
authors = ["OpenAPI Generator team and contributors"]
|
||||
description = "This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\"
|
||||
license = "Apache-2.0"
|
||||
edition = "2021"
|
||||
publish = ["crates-io"]
|
||||
|
||||
[features]
|
||||
default = ["server"]
|
||||
server = []
|
||||
conversion = [
|
||||
"frunk",
|
||||
"frunk_derives",
|
||||
"frunk_core",
|
||||
"frunk-enum-core",
|
||||
"frunk-enum-derive",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
axum = { version = "0.7" }
|
||||
axum-extra = { version = "0.9", features = ["cookie", "multipart"] }
|
||||
base64 = "0.21"
|
||||
bytes = "1"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
frunk = { version = "0.4", optional = true }
|
||||
frunk-enum-core = { version = "0.3", optional = true }
|
||||
frunk-enum-derive = { version = "0.3", optional = true }
|
||||
frunk_core = { version = "0.4", optional = true }
|
||||
frunk_derives = { version = "0.4", optional = true }
|
||||
http = "1"
|
||||
lazy_static = "1"
|
||||
regex = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
serde_urlencoded = "0.7"
|
||||
tokio = { version = "1", default-features = false, features = [
|
||||
"signal",
|
||||
"rt-multi-thread",
|
||||
] }
|
||||
tracing = { version = "0.1", features = ["attributes"] }
|
||||
uuid = { version = "1", features = ["serde"] }
|
||||
validator = { version = "0.16", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = "0.3"
|
@ -0,0 +1,91 @@
|
||||
# Rust API for petstore-with-fake-endpoints-models-for-testing
|
||||
|
||||
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
|
||||
|
||||
## Overview
|
||||
|
||||
This server was generated by the [openapi-generator]
|
||||
(https://openapi-generator.tech) project. By using the
|
||||
[OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
|
||||
server, you can easily generate a server stub.
|
||||
|
||||
To see how to make this your own, look here: [README]((https://openapi-generator.tech))
|
||||
|
||||
- API version: 1.0.0
|
||||
|
||||
|
||||
|
||||
|
||||
This autogenerated project defines an API crate `petstore-with-fake-endpoints-models-for-testing` which contains:
|
||||
* An `Api` trait defining the API in Rust.
|
||||
* Data types representing the underlying data model.
|
||||
* Axum router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
|
||||
* Request validations (path, query, body params) are included.
|
||||
|
||||
## Using the generated library
|
||||
|
||||
The generated library has a few optional features that can be activated through Cargo.
|
||||
|
||||
* `server`
|
||||
* This defaults to enabled and creates the basic skeleton of a server implementation based on Axum.
|
||||
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
|
||||
* `conversions`
|
||||
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
|
||||
|
||||
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
|
||||
|
||||
### Example
|
||||
|
||||
```rust
|
||||
struct ServerImpl {
|
||||
// database: sea_orm::DbConn,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[async_trait]
|
||||
impl petstore-with-fake-endpoints-models-for-testing::Api for ServerImpl {
|
||||
// API implementation goes here
|
||||
}
|
||||
|
||||
pub async fn start_server(addr: &str) {
|
||||
// initialize tracing
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// Init Axum router
|
||||
let app = petstore-with-fake-endpoints-models-for-testing::server::new(Arc::new(ServerImpl));
|
||||
|
||||
// Add layers to the router
|
||||
let app = app.layer(...);
|
||||
|
||||
// Run the server with graceful shutdown
|
||||
let listener = TcpListener::bind(addr).await.unwrap();
|
||||
axum::serve(listener, app)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,197 @@
|
||||
use std::{convert::TryFrom, fmt, ops::Deref};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use http::HeaderValue;
|
||||
|
||||
/// A struct to allow homogeneous conversion into a HeaderValue. We can't
|
||||
/// implement the From/Into trait on HeaderValue because we don't own
|
||||
/// either of the types.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct IntoHeaderValue<T>(pub T);
|
||||
|
||||
// Generic implementations
|
||||
|
||||
impl<T> Deref for IntoHeaderValue<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
// Derive for each TryFrom<T> in http::HeaderValue
|
||||
|
||||
macro_rules! ihv_generate {
|
||||
($t:ident) => {
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<$t> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse::<$t>() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse {} as a string: {}",
|
||||
stringify!($t),
|
||||
e
|
||||
)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse header {:?} as a string - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<$t>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<$t>) -> Result<Self, Self::Error> {
|
||||
Ok(hdr_value.0.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ihv_generate!(u64);
|
||||
ihv_generate!(i64);
|
||||
ihv_generate!(i16);
|
||||
ihv_generate!(u16);
|
||||
ihv_generate!(u32);
|
||||
ihv_generate!(usize);
|
||||
ihv_generate!(isize);
|
||||
ihv_generate!(i32);
|
||||
|
||||
// Custom derivations
|
||||
|
||||
// Vec<String>
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<Vec<String>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(
|
||||
hdr_value
|
||||
.split(',')
|
||||
.filter_map(|x| match x.trim() {
|
||||
"" => None,
|
||||
y => Some(y.to_string()),
|
||||
})
|
||||
.collect(),
|
||||
)),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse header: {:?} as a string - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<Vec<String>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<Vec<String>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.join(", ")) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} into a header - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<String> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())),
|
||||
Err(e) => Err(format!("Unable to convert header {:?} to {}", hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<String>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<String>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} from a header {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bool
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<bool> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!("Unable to parse bool from {} - {}", hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} from a header {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<bool>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<bool>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.to_string()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert: {:?} into a header: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DateTime
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<DateTime<Utc>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) {
|
||||
Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))),
|
||||
Err(e) => Err(format!("Unable to parse: {} as date - {}", hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert header {:?} to string {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<DateTime<Utc>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<DateTime<Utc>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} to a header: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,679 @@
|
||||
#![allow(
|
||||
missing_docs,
|
||||
trivial_casts,
|
||||
unused_variables,
|
||||
unused_mut,
|
||||
unused_imports,
|
||||
unused_extern_crates,
|
||||
non_camel_case_types
|
||||
)]
|
||||
#![allow(unused_imports, unused_attributes)]
|
||||
#![allow(clippy::derive_partial_eq_without_eq, clippy::disallowed_names)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use axum::extract::*;
|
||||
use axum_extra::extract::{CookieJar, Multipart};
|
||||
use bytes::Bytes;
|
||||
use http::Method;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use types::*;
|
||||
|
||||
pub const BASE_PATH: &str = "/v2";
|
||||
pub const API_VERSION: &str = "1.0.0";
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TestSpecialTagsResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(models::Client),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Call123exampleResponse {
|
||||
/// success
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum FakeOuterBooleanSerializeResponse {
|
||||
/// Output boolean
|
||||
OutputBoolean(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum FakeOuterCompositeSerializeResponse {
|
||||
/// Output composite
|
||||
OutputComposite(models::OuterComposite),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum FakeOuterNumberSerializeResponse {
|
||||
/// Output number
|
||||
OutputNumber(f64),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum FakeOuterStringSerializeResponse {
|
||||
/// Output string
|
||||
OutputString(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum FakeResponseWithNumericalDescriptionResponse {
|
||||
/// 1234
|
||||
Status200,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum HyphenParamResponse {
|
||||
/// Success
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TestBodyWithQueryParamsResponse {
|
||||
/// Success
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TestClientModelResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(models::Client),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum TestEndpointParametersResponse {
|
||||
/// Invalid username supplied
|
||||
InvalidUsernameSupplied,
|
||||
/// User not found
|
||||
UserNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum TestEnumParametersResponse {
|
||||
/// Invalid request
|
||||
InvalidRequest,
|
||||
/// Not found
|
||||
NotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TestInlineAdditionalPropertiesResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TestJsonFormDataResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TestClassnameResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(models::Client),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum AddPetResponse {
|
||||
/// Invalid input
|
||||
InvalidInput,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DeletePetResponse {
|
||||
/// Invalid pet value
|
||||
InvalidPetValue,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum FindPetsByStatusResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid status value
|
||||
InvalidStatusValue,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum FindPetsByTagsResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid tag value
|
||||
InvalidTagValue,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum GetPetByIdResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid ID supplied
|
||||
InvalidIDSupplied,
|
||||
/// Pet not found
|
||||
PetNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum UpdatePetResponse {
|
||||
/// Invalid ID supplied
|
||||
InvalidIDSupplied,
|
||||
/// Pet not found
|
||||
PetNotFound,
|
||||
/// Validation exception
|
||||
ValidationException,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum UpdatePetWithFormResponse {
|
||||
/// Invalid input
|
||||
InvalidInput,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum UploadFileResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(models::ApiResponse),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum DeleteOrderResponse {
|
||||
/// Invalid ID supplied
|
||||
InvalidIDSupplied,
|
||||
/// Order not found
|
||||
OrderNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GetInventoryResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(std::collections::HashMap<String, i32>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum GetOrderByIdResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid ID supplied
|
||||
InvalidIDSupplied,
|
||||
/// Order not found
|
||||
OrderNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum PlaceOrderResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid Order
|
||||
InvalidOrder,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CreateUserResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CreateUsersWithArrayInputResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CreateUsersWithListInputResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum DeleteUserResponse {
|
||||
/// Invalid username supplied
|
||||
InvalidUsernameSupplied,
|
||||
/// User not found
|
||||
UserNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum GetUserByNameResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid username supplied
|
||||
InvalidUsernameSupplied,
|
||||
/// User not found
|
||||
UserNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum LoginUserResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation {
|
||||
body: String,
|
||||
x_rate_limit: Option<i32>,
|
||||
x_expires_after: Option<chrono::DateTime<chrono::Utc>>,
|
||||
},
|
||||
/// Invalid username/password supplied
|
||||
InvalidUsername,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LogoutUserResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum UpdateUserResponse {
|
||||
/// Invalid user supplied
|
||||
InvalidUserSupplied,
|
||||
/// User not found
|
||||
UserNotFound,
|
||||
}
|
||||
|
||||
/// API
|
||||
#[async_trait]
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub trait Api {
|
||||
/// To test special tags.
|
||||
///
|
||||
/// TestSpecialTags - PATCH /v2/another-fake/dummy
|
||||
async fn test_special_tags(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::Client,
|
||||
) -> Result<TestSpecialTagsResponse, String>;
|
||||
|
||||
/// Call123example - GET /v2/fake/operation-with-numeric-id
|
||||
async fn call123example(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<Call123exampleResponse, String>;
|
||||
|
||||
/// FakeOuterBooleanSerialize - POST /v2/fake/outer/boolean
|
||||
async fn fake_outer_boolean_serialize(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Option<models::OuterBoolean>,
|
||||
) -> Result<FakeOuterBooleanSerializeResponse, String>;
|
||||
|
||||
/// FakeOuterCompositeSerialize - POST /v2/fake/outer/composite
|
||||
async fn fake_outer_composite_serialize(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Option<models::OuterComposite>,
|
||||
) -> Result<FakeOuterCompositeSerializeResponse, String>;
|
||||
|
||||
/// FakeOuterNumberSerialize - POST /v2/fake/outer/number
|
||||
async fn fake_outer_number_serialize(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Option<models::OuterNumber>,
|
||||
) -> Result<FakeOuterNumberSerializeResponse, String>;
|
||||
|
||||
/// FakeOuterStringSerialize - POST /v2/fake/outer/string
|
||||
async fn fake_outer_string_serialize(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Option<models::OuterString>,
|
||||
) -> Result<FakeOuterStringSerializeResponse, String>;
|
||||
|
||||
/// FakeResponseWithNumericalDescription - GET /v2/fake/response-with-numerical-description
|
||||
async fn fake_response_with_numerical_description(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<FakeResponseWithNumericalDescriptionResponse, String>;
|
||||
|
||||
/// HyphenParam - GET /v2/fake/hyphenParam/{hyphen-param}
|
||||
async fn hyphen_param(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::HyphenParamPathParams,
|
||||
) -> Result<HyphenParamResponse, String>;
|
||||
|
||||
/// TestBodyWithQueryParams - PUT /v2/fake/body-with-query-params
|
||||
async fn test_body_with_query_params(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::TestBodyWithQueryParamsQueryParams,
|
||||
body: models::User,
|
||||
) -> Result<TestBodyWithQueryParamsResponse, String>;
|
||||
|
||||
/// To test \"client\" model.
|
||||
///
|
||||
/// TestClientModel - PATCH /v2/fake
|
||||
async fn test_client_model(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::Client,
|
||||
) -> Result<TestClientModelResponse, String>;
|
||||
|
||||
/// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트.
|
||||
///
|
||||
/// TestEndpointParameters - POST /v2/fake
|
||||
async fn test_endpoint_parameters(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<TestEndpointParametersResponse, String>;
|
||||
|
||||
/// To test enum parameters.
|
||||
///
|
||||
/// TestEnumParameters - GET /v2/fake
|
||||
async fn test_enum_parameters(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
header_params: models::TestEnumParametersHeaderParams,
|
||||
query_params: models::TestEnumParametersQueryParams,
|
||||
) -> Result<TestEnumParametersResponse, String>;
|
||||
|
||||
/// test inline additionalProperties.
|
||||
///
|
||||
/// TestInlineAdditionalProperties - POST /v2/fake/inline-additionalProperties
|
||||
async fn test_inline_additional_properties(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: std::collections::HashMap<String, String>,
|
||||
) -> Result<TestInlineAdditionalPropertiesResponse, String>;
|
||||
|
||||
/// test json serialization of form data.
|
||||
///
|
||||
/// TestJsonFormData - GET /v2/fake/jsonFormData
|
||||
async fn test_json_form_data(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<TestJsonFormDataResponse, String>;
|
||||
|
||||
/// To test class name in snake case.
|
||||
///
|
||||
/// TestClassname - PATCH /v2/fake_classname_test
|
||||
async fn test_classname(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::Client,
|
||||
) -> Result<TestClassnameResponse, String>;
|
||||
|
||||
/// Add a new pet to the store.
|
||||
///
|
||||
/// AddPet - POST /v2/pet
|
||||
async fn add_pet(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::Pet,
|
||||
) -> Result<AddPetResponse, String>;
|
||||
|
||||
/// Deletes a pet.
|
||||
///
|
||||
/// DeletePet - DELETE /v2/pet/{petId}
|
||||
async fn delete_pet(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
header_params: models::DeletePetHeaderParams,
|
||||
path_params: models::DeletePetPathParams,
|
||||
) -> Result<DeletePetResponse, String>;
|
||||
|
||||
/// Finds Pets by status.
|
||||
///
|
||||
/// FindPetsByStatus - GET /v2/pet/findByStatus
|
||||
async fn find_pets_by_status(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::FindPetsByStatusQueryParams,
|
||||
) -> Result<FindPetsByStatusResponse, String>;
|
||||
|
||||
/// Finds Pets by tags.
|
||||
///
|
||||
/// FindPetsByTags - GET /v2/pet/findByTags
|
||||
async fn find_pets_by_tags(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::FindPetsByTagsQueryParams,
|
||||
) -> Result<FindPetsByTagsResponse, String>;
|
||||
|
||||
/// Find pet by ID.
|
||||
///
|
||||
/// GetPetById - GET /v2/pet/{petId}
|
||||
async fn get_pet_by_id(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::GetPetByIdPathParams,
|
||||
) -> Result<GetPetByIdResponse, String>;
|
||||
|
||||
/// Update an existing pet.
|
||||
///
|
||||
/// UpdatePet - PUT /v2/pet
|
||||
async fn update_pet(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::Pet,
|
||||
) -> Result<UpdatePetResponse, String>;
|
||||
|
||||
/// Updates a pet in the store with form data.
|
||||
///
|
||||
/// UpdatePetWithForm - POST /v2/pet/{petId}
|
||||
async fn update_pet_with_form(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::UpdatePetWithFormPathParams,
|
||||
) -> Result<UpdatePetWithFormResponse, String>;
|
||||
|
||||
/// uploads an image.
|
||||
///
|
||||
/// UploadFile - POST /v2/pet/{petId}/uploadImage
|
||||
async fn upload_file(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::UploadFilePathParams,
|
||||
body: Multipart,
|
||||
) -> Result<UploadFileResponse, String>;
|
||||
|
||||
/// Delete purchase order by ID.
|
||||
///
|
||||
/// DeleteOrder - DELETE /v2/store/order/{order_id}
|
||||
async fn delete_order(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::DeleteOrderPathParams,
|
||||
) -> Result<DeleteOrderResponse, String>;
|
||||
|
||||
/// Returns pet inventories by status.
|
||||
///
|
||||
/// GetInventory - GET /v2/store/inventory
|
||||
async fn get_inventory(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<GetInventoryResponse, String>;
|
||||
|
||||
/// Find purchase order by ID.
|
||||
///
|
||||
/// GetOrderById - GET /v2/store/order/{order_id}
|
||||
async fn get_order_by_id(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::GetOrderByIdPathParams,
|
||||
) -> Result<GetOrderByIdResponse, String>;
|
||||
|
||||
/// Place an order for a pet.
|
||||
///
|
||||
/// PlaceOrder - POST /v2/store/order
|
||||
async fn place_order(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::Order,
|
||||
) -> Result<PlaceOrderResponse, String>;
|
||||
|
||||
/// Create user.
|
||||
///
|
||||
/// CreateUser - POST /v2/user
|
||||
async fn create_user(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::User,
|
||||
) -> Result<CreateUserResponse, String>;
|
||||
|
||||
/// Creates list of users with given input array.
|
||||
///
|
||||
/// CreateUsersWithArrayInput - POST /v2/user/createWithArray
|
||||
async fn create_users_with_array_input(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Vec<models::User>,
|
||||
) -> Result<CreateUsersWithArrayInputResponse, String>;
|
||||
|
||||
/// Creates list of users with given input array.
|
||||
///
|
||||
/// CreateUsersWithListInput - POST /v2/user/createWithList
|
||||
async fn create_users_with_list_input(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Vec<models::User>,
|
||||
) -> Result<CreateUsersWithListInputResponse, String>;
|
||||
|
||||
/// Delete user.
|
||||
///
|
||||
/// DeleteUser - DELETE /v2/user/{username}
|
||||
async fn delete_user(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::DeleteUserPathParams,
|
||||
) -> Result<DeleteUserResponse, String>;
|
||||
|
||||
/// Get user by user name.
|
||||
///
|
||||
/// GetUserByName - GET /v2/user/{username}
|
||||
async fn get_user_by_name(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::GetUserByNamePathParams,
|
||||
) -> Result<GetUserByNameResponse, String>;
|
||||
|
||||
/// Logs user into the system.
|
||||
///
|
||||
/// LoginUser - GET /v2/user/login
|
||||
async fn login_user(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::LoginUserQueryParams,
|
||||
) -> Result<LoginUserResponse, String>;
|
||||
|
||||
/// Logs out current logged in user session.
|
||||
///
|
||||
/// LogoutUser - GET /v2/user/logout
|
||||
async fn logout_user(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<LogoutUserResponse, String>;
|
||||
|
||||
/// Updated user.
|
||||
///
|
||||
/// UpdateUser - PUT /v2/user/{username}
|
||||
async fn update_user(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::UpdateUserPathParams,
|
||||
body: models::User,
|
||||
) -> Result<UpdateUserResponse, String>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub mod server;
|
||||
|
||||
pub mod models;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub(crate) mod header;
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,665 @@
|
||||
use std::{mem, str::FromStr};
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Object(serde_json::Value);
|
||||
|
||||
impl validator::Validate for Object {
|
||||
fn validate(&self) -> Result<(), validator::ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Object {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(serde_json::Value::String(s.to_owned())))
|
||||
}
|
||||
}
|
||||
|
||||
/// Serde helper function to create a default `Option<Nullable<T>>` while
|
||||
/// deserializing
|
||||
pub fn default_optional_nullable<T>() -> Option<Nullable<T>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Serde helper function to deserialize into an `Option<Nullable<T>>`
|
||||
pub fn deserialize_optional_nullable<'de, D, T>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<Nullable<T>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
Option::<T>::deserialize(deserializer).map(|val| match val {
|
||||
Some(inner) => Some(Nullable::Present(inner)),
|
||||
None => Some(Nullable::Null),
|
||||
})
|
||||
}
|
||||
|
||||
/// The Nullable type. Represents a value which may be specified as null on an API.
|
||||
/// Note that this is distinct from a value that is optional and not present!
|
||||
///
|
||||
/// Nullable implements many of the same methods as the Option type (map, unwrap, etc).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum Nullable<T> {
|
||||
/// Null value
|
||||
Null,
|
||||
/// Value is present
|
||||
Present(T),
|
||||
}
|
||||
|
||||
impl<T> Nullable<T> {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `true` if the Nullable is a `Present` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_present(), true);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_present(), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_present(&self) -> bool {
|
||||
match *self {
|
||||
Nullable::Present(_) => true,
|
||||
Nullable::Null => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the Nullable is a `Null` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_null(), false);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_null(), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_null(&self) -> bool {
|
||||
!self.is_present()
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert an `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, preserving the original.
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take a `Nullable` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: enum.Nullable.html#method.map
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let num_as_str: Nullable<String> = Nullable::Present("10".to_string());
|
||||
/// // First, cast `Nullable<String>` to `Nullable<&String>` with `as_ref`,
|
||||
/// // then consume *that* with `map`, leaving `num_as_str` on the stack.
|
||||
/// let num_as_int: Nullable<usize> = num_as_str.as_ref().map(|n| n.len());
|
||||
/// println!("still can print num_as_str: {:?}", num_as_str);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_ref(&self) -> Nullable<&T> {
|
||||
match *self {
|
||||
Nullable::Present(ref x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// match x.as_mut() {
|
||||
/// Nullable::Present(v) => *v = 42,
|
||||
/// Nullable::Null => {},
|
||||
/// }
|
||||
/// assert_eq!(x, Nullable::Present(42));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut(&mut self) -> Nullable<&mut T> {
|
||||
match *self {
|
||||
Nullable::Present(ref mut x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Getting to contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Unwraps a Nullable, yielding the content of a `Nullable::Present`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is a [`Nullable::Null`] with a custom panic message provided by
|
||||
/// `msg`.
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("value");
|
||||
/// assert_eq!(x.expect("the world is ending"), "value");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// x.expect("the world is ending"); // panics with `the world is ending`
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn expect(self, msg: &str) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => expect_failed(msg),
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves the value `v` out of the `Nullable<T>` if it is `Nullable::Present(v)`.
|
||||
///
|
||||
/// In general, because this function may panic, its use is discouraged.
|
||||
/// Instead, prefer to use pattern matching and handle the `Nullable::Null`
|
||||
/// case explicitly.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the self value equals [`Nullable::Null`].
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("air");
|
||||
/// assert_eq!(x.unwrap(), "air");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.unwrap(), "air"); // fails
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => panic!("called `Nullable::unwrap()` on a `Nullable::Null` value"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or a default.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("car").unwrap_or("bike"), "car");
|
||||
/// assert_eq!(Nullable::Null.unwrap_or("bike"), "bike");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or(self, def: T) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => def,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or computes it from a closure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let k = 10;
|
||||
/// assert_eq!(Nullable::Present(4).unwrap_or_else(|| 2 * k), 4);
|
||||
/// assert_eq!(Nullable::Null.unwrap_or_else(|| 2 * k), 20);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Transforming contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps a `Nullable<T>` to `Nullable<U>` by applying a function to a contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert a `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, consuming the original:
|
||||
///
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let maybe_some_string = Nullable::Present(String::from("Hello, World!"));
|
||||
/// // `Nullable::map` takes self *by value*, consuming `maybe_some_string`
|
||||
/// let maybe_some_len = maybe_some_string.map(|s| s.len());
|
||||
///
|
||||
/// assert_eq!(maybe_some_len, Nullable::Present(13));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => Nullable::Present(f(x)),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or returns a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or computes a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let k = 21;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err)`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or(0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or(0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err())`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err()),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Boolean operations on the values, eager and lazy
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Present("foo"));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and<U>(self, optb: Nullable<U>) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(_) => optb,
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise calls `f` with the
|
||||
/// wrapped value and returns the result.
|
||||
///
|
||||
/// Some languages call this operation flatmap.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// fn sq(x: u32) -> Nullable<u32> { Nullable::Present(x * x) }
|
||||
/// fn nope(_: u32) -> Nullable<u32> { Nullable::Null }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(sq), Nullable::Present(16));
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(nope), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Present(2).and_then(nope).and_then(sq), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Null.and_then(sq).and_then(sq), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and_then<U, F: FnOnce(T) -> Nullable<U>>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => f(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x = Nullable::Null;
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(100));
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or(self, optb: Nullable<T>) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => optb,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise calls `f` and
|
||||
/// returns the result.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// fn nobody() -> Nullable<&'static str> { Nullable::Null }
|
||||
/// fn vikings() -> Nullable<&'static str> { Nullable::Present("vikings") }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("barbarians").or_else(vikings),
|
||||
/// Nullable::Present("barbarians"));
|
||||
/// assert_eq!(Nullable::Null.or_else(vikings), Nullable::Present("vikings"));
|
||||
/// assert_eq!(Nullable::Null.or_else(nobody), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Takes the value out of the Nullable, leaving a `Nullable::Null` in its place.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
///
|
||||
/// let mut x: Nullable<u32> = Nullable::Null;
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn take(&mut self) -> Nullable<T> {
|
||||
mem::replace(self, Nullable::Null)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> Nullable<&'a T> {
|
||||
/// Maps an `Nullable<&T>` to an `Nullable<T>` by cloning the contents of the
|
||||
/// Nullable.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x = 12;
|
||||
/// let opt_x = Nullable::Present(&x);
|
||||
/// assert_eq!(opt_x, Nullable::Present(&12));
|
||||
/// let cloned = opt_x.cloned();
|
||||
/// assert_eq!(cloned, Nullable::Present(12));
|
||||
/// ```
|
||||
pub fn cloned(self) -> Nullable<T> {
|
||||
self.map(Clone::clone)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Nullable<T> {
|
||||
/// Returns the contained value or a default
|
||||
///
|
||||
/// Consumes the `self` argument then, if `Nullable::Present`, returns the contained
|
||||
/// value, otherwise if `Nullable::Null`, returns the default value for that
|
||||
/// type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore_with_fake_endpoints_models_for_testing::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(42);
|
||||
/// assert_eq!(42, x.unwrap_or_default());
|
||||
///
|
||||
/// let y: Nullable<i32> = Nullable::Null;
|
||||
/// assert_eq!(0, y.unwrap_or_default());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_default(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Nullable<T> {
|
||||
/// Returns None.
|
||||
#[inline]
|
||||
fn default() -> Nullable<T> {
|
||||
Nullable::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Nullable<T> {
|
||||
fn from(val: T) -> Nullable<T> {
|
||||
Nullable::Present(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Nullable<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
Nullable::Present(ref inner) => serializer.serialize_some(&inner),
|
||||
Nullable::Null => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Nullable<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Nullable<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// In order to deserialize a required, but nullable, value, we first have to check whether
|
||||
// the value is present at all. To do this, we deserialize to a serde_json::Value, which
|
||||
// fails if the value is missing, or gives serde_json::Value::Null if the value is present.
|
||||
// If that succeeds as null, we can easily return a Null.
|
||||
// If that succeeds as some value, we deserialize that value and return a Present.
|
||||
// If that errors, we return the error.
|
||||
let presence: Result<::serde_json::Value, _> =
|
||||
serde::Deserialize::deserialize(deserializer);
|
||||
match presence {
|
||||
Ok(serde_json::Value::Null) => Ok(Nullable::Null),
|
||||
Ok(some_value) => serde_json::from_value(some_value)
|
||||
.map(Nullable::Present)
|
||||
.map_err(serde::de::Error::custom),
|
||||
Err(x) => Err(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn expect_failed(msg: &str) -> ! {
|
||||
panic!("{}", msg)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
/// Base64-encoded byte array
|
||||
pub struct ByteArray(pub Vec<u8>);
|
||||
|
||||
impl Serialize for ByteArray {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&general_purpose::STANDARD.encode(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ByteArray {
|
||||
fn deserialize<D>(deserializer: D) -> Result<ByteArray, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
match general_purpose::STANDARD.decode(s) {
|
||||
Ok(bin) => Ok(ByteArray(bin)),
|
||||
_ => Err(serde::de::Error::custom("invalid base64")),
|
||||
}
|
||||
}
|
||||
}
|
2
samples/server/petstore/rust-axum/output/petstore/.gitignore
vendored
Normal file
2
samples/server/petstore/rust-axum/output/petstore/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1,8 @@
|
||||
.gitignore
|
||||
Cargo.toml
|
||||
README.md
|
||||
src/header.rs
|
||||
src/lib.rs
|
||||
src/models.rs
|
||||
src/server/mod.rs
|
||||
src/types.rs
|
@ -0,0 +1 @@
|
||||
7.3.0-SNAPSHOT
|
47
samples/server/petstore/rust-axum/output/petstore/Cargo.toml
Normal file
47
samples/server/petstore/rust-axum/output/petstore/Cargo.toml
Normal file
@ -0,0 +1,47 @@
|
||||
[package]
|
||||
name = "petstore"
|
||||
version = "1.0.0"
|
||||
authors = ["OpenAPI Generator team and contributors"]
|
||||
description = "This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters."
|
||||
license = "Apache-2.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["server"]
|
||||
server = []
|
||||
conversion = [
|
||||
"frunk",
|
||||
"frunk_derives",
|
||||
"frunk_core",
|
||||
"frunk-enum-core",
|
||||
"frunk-enum-derive",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
axum = { version = "0.7" }
|
||||
axum-extra = { version = "0.9", features = ["cookie", "multipart"] }
|
||||
base64 = "0.21"
|
||||
bytes = "1"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
frunk = { version = "0.4", optional = true }
|
||||
frunk-enum-core = { version = "0.3", optional = true }
|
||||
frunk-enum-derive = { version = "0.3", optional = true }
|
||||
frunk_core = { version = "0.4", optional = true }
|
||||
frunk_derives = { version = "0.4", optional = true }
|
||||
http = "1"
|
||||
lazy_static = "1"
|
||||
regex = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
serde_urlencoded = "0.7"
|
||||
tokio = { version = "1", default-features = false, features = [
|
||||
"signal",
|
||||
"rt-multi-thread",
|
||||
] }
|
||||
tracing = { version = "0.1", features = ["attributes"] }
|
||||
uuid = { version = "1", features = ["serde"] }
|
||||
validator = { version = "0.16", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = "0.3"
|
91
samples/server/petstore/rust-axum/output/petstore/README.md
Normal file
91
samples/server/petstore/rust-axum/output/petstore/README.md
Normal file
@ -0,0 +1,91 @@
|
||||
# Rust API for petstore
|
||||
|
||||
This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
|
||||
|
||||
## Overview
|
||||
|
||||
This server was generated by the [openapi-generator]
|
||||
(https://openapi-generator.tech) project. By using the
|
||||
[OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
|
||||
server, you can easily generate a server stub.
|
||||
|
||||
To see how to make this your own, look here: [README]((https://openapi-generator.tech))
|
||||
|
||||
- API version: 1.0.0
|
||||
|
||||
|
||||
|
||||
|
||||
This autogenerated project defines an API crate `petstore` which contains:
|
||||
* An `Api` trait defining the API in Rust.
|
||||
* Data types representing the underlying data model.
|
||||
* Axum router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
|
||||
* Request validations (path, query, body params) are included.
|
||||
|
||||
## Using the generated library
|
||||
|
||||
The generated library has a few optional features that can be activated through Cargo.
|
||||
|
||||
* `server`
|
||||
* This defaults to enabled and creates the basic skeleton of a server implementation based on Axum.
|
||||
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
|
||||
* `conversions`
|
||||
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
|
||||
|
||||
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
|
||||
|
||||
### Example
|
||||
|
||||
```rust
|
||||
struct ServerImpl {
|
||||
// database: sea_orm::DbConn,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[async_trait]
|
||||
impl petstore::Api for ServerImpl {
|
||||
// API implementation goes here
|
||||
}
|
||||
|
||||
pub async fn start_server(addr: &str) {
|
||||
// initialize tracing
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// Init Axum router
|
||||
let app = petstore::server::new(Arc::new(ServerImpl));
|
||||
|
||||
// Add layers to the router
|
||||
let app = app.layer(...);
|
||||
|
||||
// Run the server with graceful shutdown
|
||||
let listener = TcpListener::bind(addr).await.unwrap();
|
||||
axum::serve(listener, app)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
}
|
||||
```
|
197
samples/server/petstore/rust-axum/output/petstore/src/header.rs
Normal file
197
samples/server/petstore/rust-axum/output/petstore/src/header.rs
Normal file
@ -0,0 +1,197 @@
|
||||
use std::{convert::TryFrom, fmt, ops::Deref};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use http::HeaderValue;
|
||||
|
||||
/// A struct to allow homogeneous conversion into a HeaderValue. We can't
|
||||
/// implement the From/Into trait on HeaderValue because we don't own
|
||||
/// either of the types.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct IntoHeaderValue<T>(pub T);
|
||||
|
||||
// Generic implementations
|
||||
|
||||
impl<T> Deref for IntoHeaderValue<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
// Derive for each TryFrom<T> in http::HeaderValue
|
||||
|
||||
macro_rules! ihv_generate {
|
||||
($t:ident) => {
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<$t> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse::<$t>() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse {} as a string: {}",
|
||||
stringify!($t),
|
||||
e
|
||||
)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse header {:?} as a string - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<$t>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<$t>) -> Result<Self, Self::Error> {
|
||||
Ok(hdr_value.0.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ihv_generate!(u64);
|
||||
ihv_generate!(i64);
|
||||
ihv_generate!(i16);
|
||||
ihv_generate!(u16);
|
||||
ihv_generate!(u32);
|
||||
ihv_generate!(usize);
|
||||
ihv_generate!(isize);
|
||||
ihv_generate!(i32);
|
||||
|
||||
// Custom derivations
|
||||
|
||||
// Vec<String>
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<Vec<String>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(
|
||||
hdr_value
|
||||
.split(',')
|
||||
.filter_map(|x| match x.trim() {
|
||||
"" => None,
|
||||
y => Some(y.to_string()),
|
||||
})
|
||||
.collect(),
|
||||
)),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse header: {:?} as a string - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<Vec<String>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<Vec<String>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.join(", ")) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} into a header - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<String> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())),
|
||||
Err(e) => Err(format!("Unable to convert header {:?} to {}", hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<String>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<String>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} from a header {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bool
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<bool> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!("Unable to parse bool from {} - {}", hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} from a header {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<bool>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<bool>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.to_string()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert: {:?} into a header: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DateTime
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<DateTime<Utc>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) {
|
||||
Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))),
|
||||
Err(e) => Err(format!("Unable to parse: {} as date - {}", hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert header {:?} to string {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<DateTime<Utc>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<DateTime<Utc>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} to a header: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
441
samples/server/petstore/rust-axum/output/petstore/src/lib.rs
Normal file
441
samples/server/petstore/rust-axum/output/petstore/src/lib.rs
Normal file
@ -0,0 +1,441 @@
|
||||
#![allow(
|
||||
missing_docs,
|
||||
trivial_casts,
|
||||
unused_variables,
|
||||
unused_mut,
|
||||
unused_imports,
|
||||
unused_extern_crates,
|
||||
non_camel_case_types
|
||||
)]
|
||||
#![allow(unused_imports, unused_attributes)]
|
||||
#![allow(clippy::derive_partial_eq_without_eq, clippy::disallowed_names)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use axum::extract::*;
|
||||
use axum_extra::extract::{CookieJar, Multipart};
|
||||
use bytes::Bytes;
|
||||
use http::Method;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use types::*;
|
||||
|
||||
pub const BASE_PATH: &str = "/v2";
|
||||
pub const API_VERSION: &str = "1.0.0";
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum AddPetResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid input
|
||||
InvalidInput,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DeletePetResponse {
|
||||
/// Invalid pet value
|
||||
InvalidPetValue,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum FindPetsByStatusResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid status value
|
||||
InvalidStatusValue,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum FindPetsByTagsResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid tag value
|
||||
InvalidTagValue,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum GetPetByIdResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid ID supplied
|
||||
InvalidIDSupplied,
|
||||
/// Pet not found
|
||||
PetNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum UpdatePetResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid ID supplied
|
||||
InvalidIDSupplied,
|
||||
/// Pet not found
|
||||
PetNotFound,
|
||||
/// Validation exception
|
||||
ValidationException,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum UpdatePetWithFormResponse {
|
||||
/// Invalid input
|
||||
InvalidInput,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum UploadFileResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(models::ApiResponse),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum DeleteOrderResponse {
|
||||
/// Invalid ID supplied
|
||||
InvalidIDSupplied,
|
||||
/// Order not found
|
||||
OrderNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GetInventoryResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(std::collections::HashMap<String, i32>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum GetOrderByIdResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid ID supplied
|
||||
InvalidIDSupplied,
|
||||
/// Order not found
|
||||
OrderNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum PlaceOrderResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid Order
|
||||
InvalidOrder,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CreateUserResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CreateUsersWithArrayInputResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CreateUsersWithListInputResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum DeleteUserResponse {
|
||||
/// Invalid username supplied
|
||||
InvalidUsernameSupplied,
|
||||
/// User not found
|
||||
UserNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum GetUserByNameResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation(String),
|
||||
/// Invalid username supplied
|
||||
InvalidUsernameSupplied,
|
||||
/// User not found
|
||||
UserNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum LoginUserResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation {
|
||||
body: String,
|
||||
set_cookie: Option<String>,
|
||||
x_rate_limit: Option<i32>,
|
||||
x_expires_after: Option<chrono::DateTime<chrono::Utc>>,
|
||||
},
|
||||
/// Invalid username/password supplied
|
||||
InvalidUsername,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LogoutUserResponse {
|
||||
/// successful operation
|
||||
SuccessfulOperation,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[must_use]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum UpdateUserResponse {
|
||||
/// Invalid user supplied
|
||||
InvalidUserSupplied,
|
||||
/// User not found
|
||||
UserNotFound,
|
||||
}
|
||||
|
||||
/// API
|
||||
#[async_trait]
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub trait Api {
|
||||
/// Add a new pet to the store.
|
||||
///
|
||||
/// AddPet - POST /v2/pet
|
||||
async fn add_pet(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::Pet,
|
||||
) -> Result<AddPetResponse, String>;
|
||||
|
||||
/// Deletes a pet.
|
||||
///
|
||||
/// DeletePet - DELETE /v2/pet/{petId}
|
||||
async fn delete_pet(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
header_params: models::DeletePetHeaderParams,
|
||||
path_params: models::DeletePetPathParams,
|
||||
) -> Result<DeletePetResponse, String>;
|
||||
|
||||
/// Finds Pets by status.
|
||||
///
|
||||
/// FindPetsByStatus - GET /v2/pet/findByStatus
|
||||
async fn find_pets_by_status(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::FindPetsByStatusQueryParams,
|
||||
) -> Result<FindPetsByStatusResponse, String>;
|
||||
|
||||
/// Finds Pets by tags.
|
||||
///
|
||||
/// FindPetsByTags - GET /v2/pet/findByTags
|
||||
async fn find_pets_by_tags(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::FindPetsByTagsQueryParams,
|
||||
) -> Result<FindPetsByTagsResponse, String>;
|
||||
|
||||
/// Find pet by ID.
|
||||
///
|
||||
/// GetPetById - GET /v2/pet/{petId}
|
||||
async fn get_pet_by_id(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::GetPetByIdPathParams,
|
||||
) -> Result<GetPetByIdResponse, String>;
|
||||
|
||||
/// Update an existing pet.
|
||||
///
|
||||
/// UpdatePet - PUT /v2/pet
|
||||
async fn update_pet(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::Pet,
|
||||
) -> Result<UpdatePetResponse, String>;
|
||||
|
||||
/// Updates a pet in the store with form data.
|
||||
///
|
||||
/// UpdatePetWithForm - POST /v2/pet/{petId}
|
||||
async fn update_pet_with_form(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::UpdatePetWithFormPathParams,
|
||||
) -> Result<UpdatePetWithFormResponse, String>;
|
||||
|
||||
/// uploads an image.
|
||||
///
|
||||
/// UploadFile - POST /v2/pet/{petId}/uploadImage
|
||||
async fn upload_file(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::UploadFilePathParams,
|
||||
body: Multipart,
|
||||
) -> Result<UploadFileResponse, String>;
|
||||
|
||||
/// Delete purchase order by ID.
|
||||
///
|
||||
/// DeleteOrder - DELETE /v2/store/order/{orderId}
|
||||
async fn delete_order(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::DeleteOrderPathParams,
|
||||
) -> Result<DeleteOrderResponse, String>;
|
||||
|
||||
/// Returns pet inventories by status.
|
||||
///
|
||||
/// GetInventory - GET /v2/store/inventory
|
||||
async fn get_inventory(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<GetInventoryResponse, String>;
|
||||
|
||||
/// Find purchase order by ID.
|
||||
///
|
||||
/// GetOrderById - GET /v2/store/order/{orderId}
|
||||
async fn get_order_by_id(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::GetOrderByIdPathParams,
|
||||
) -> Result<GetOrderByIdResponse, String>;
|
||||
|
||||
/// Place an order for a pet.
|
||||
///
|
||||
/// PlaceOrder - POST /v2/store/order
|
||||
async fn place_order(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::Order,
|
||||
) -> Result<PlaceOrderResponse, String>;
|
||||
|
||||
/// Create user.
|
||||
///
|
||||
/// CreateUser - POST /v2/user
|
||||
async fn create_user(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: models::User,
|
||||
) -> Result<CreateUserResponse, String>;
|
||||
|
||||
/// Creates list of users with given input array.
|
||||
///
|
||||
/// CreateUsersWithArrayInput - POST /v2/user/createWithArray
|
||||
async fn create_users_with_array_input(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Vec<models::User>,
|
||||
) -> Result<CreateUsersWithArrayInputResponse, String>;
|
||||
|
||||
/// Creates list of users with given input array.
|
||||
///
|
||||
/// CreateUsersWithListInput - POST /v2/user/createWithList
|
||||
async fn create_users_with_list_input(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
body: Vec<models::User>,
|
||||
) -> Result<CreateUsersWithListInputResponse, String>;
|
||||
|
||||
/// Delete user.
|
||||
///
|
||||
/// DeleteUser - DELETE /v2/user/{username}
|
||||
async fn delete_user(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::DeleteUserPathParams,
|
||||
) -> Result<DeleteUserResponse, String>;
|
||||
|
||||
/// Get user by user name.
|
||||
///
|
||||
/// GetUserByName - GET /v2/user/{username}
|
||||
async fn get_user_by_name(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::GetUserByNamePathParams,
|
||||
) -> Result<GetUserByNameResponse, String>;
|
||||
|
||||
/// Logs user into the system.
|
||||
///
|
||||
/// LoginUser - GET /v2/user/login
|
||||
async fn login_user(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
query_params: models::LoginUserQueryParams,
|
||||
) -> Result<LoginUserResponse, String>;
|
||||
|
||||
/// Logs out current logged in user session.
|
||||
///
|
||||
/// LogoutUser - GET /v2/user/logout
|
||||
async fn logout_user(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<LogoutUserResponse, String>;
|
||||
|
||||
/// Updated user.
|
||||
///
|
||||
/// UpdateUser - PUT /v2/user/{username}
|
||||
async fn update_user(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
path_params: models::UpdateUserPathParams,
|
||||
body: models::User,
|
||||
) -> Result<UpdateUserResponse, String>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub mod server;
|
||||
|
||||
pub mod models;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub(crate) mod header;
|
1215
samples/server/petstore/rust-axum/output/petstore/src/models.rs
Normal file
1215
samples/server/petstore/rust-axum/output/petstore/src/models.rs
Normal file
File diff suppressed because it is too large
Load Diff
1630
samples/server/petstore/rust-axum/output/petstore/src/server/mod.rs
Normal file
1630
samples/server/petstore/rust-axum/output/petstore/src/server/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
665
samples/server/petstore/rust-axum/output/petstore/src/types.rs
Normal file
665
samples/server/petstore/rust-axum/output/petstore/src/types.rs
Normal file
@ -0,0 +1,665 @@
|
||||
use std::{mem, str::FromStr};
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Object(serde_json::Value);
|
||||
|
||||
impl validator::Validate for Object {
|
||||
fn validate(&self) -> Result<(), validator::ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Object {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(serde_json::Value::String(s.to_owned())))
|
||||
}
|
||||
}
|
||||
|
||||
/// Serde helper function to create a default `Option<Nullable<T>>` while
|
||||
/// deserializing
|
||||
pub fn default_optional_nullable<T>() -> Option<Nullable<T>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Serde helper function to deserialize into an `Option<Nullable<T>>`
|
||||
pub fn deserialize_optional_nullable<'de, D, T>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<Nullable<T>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
Option::<T>::deserialize(deserializer).map(|val| match val {
|
||||
Some(inner) => Some(Nullable::Present(inner)),
|
||||
None => Some(Nullable::Null),
|
||||
})
|
||||
}
|
||||
|
||||
/// The Nullable type. Represents a value which may be specified as null on an API.
|
||||
/// Note that this is distinct from a value that is optional and not present!
|
||||
///
|
||||
/// Nullable implements many of the same methods as the Option type (map, unwrap, etc).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum Nullable<T> {
|
||||
/// Null value
|
||||
Null,
|
||||
/// Value is present
|
||||
Present(T),
|
||||
}
|
||||
|
||||
impl<T> Nullable<T> {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `true` if the Nullable is a `Present` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_present(), true);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_present(), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_present(&self) -> bool {
|
||||
match *self {
|
||||
Nullable::Present(_) => true,
|
||||
Nullable::Null => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the Nullable is a `Null` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_null(), false);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_null(), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_null(&self) -> bool {
|
||||
!self.is_present()
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert an `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, preserving the original.
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take a `Nullable` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: enum.Nullable.html#method.map
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let num_as_str: Nullable<String> = Nullable::Present("10".to_string());
|
||||
/// // First, cast `Nullable<String>` to `Nullable<&String>` with `as_ref`,
|
||||
/// // then consume *that* with `map`, leaving `num_as_str` on the stack.
|
||||
/// let num_as_int: Nullable<usize> = num_as_str.as_ref().map(|n| n.len());
|
||||
/// println!("still can print num_as_str: {:?}", num_as_str);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_ref(&self) -> Nullable<&T> {
|
||||
match *self {
|
||||
Nullable::Present(ref x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// match x.as_mut() {
|
||||
/// Nullable::Present(v) => *v = 42,
|
||||
/// Nullable::Null => {},
|
||||
/// }
|
||||
/// assert_eq!(x, Nullable::Present(42));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut(&mut self) -> Nullable<&mut T> {
|
||||
match *self {
|
||||
Nullable::Present(ref mut x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Getting to contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Unwraps a Nullable, yielding the content of a `Nullable::Present`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is a [`Nullable::Null`] with a custom panic message provided by
|
||||
/// `msg`.
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("value");
|
||||
/// assert_eq!(x.expect("the world is ending"), "value");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// x.expect("the world is ending"); // panics with `the world is ending`
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn expect(self, msg: &str) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => expect_failed(msg),
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves the value `v` out of the `Nullable<T>` if it is `Nullable::Present(v)`.
|
||||
///
|
||||
/// In general, because this function may panic, its use is discouraged.
|
||||
/// Instead, prefer to use pattern matching and handle the `Nullable::Null`
|
||||
/// case explicitly.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the self value equals [`Nullable::Null`].
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("air");
|
||||
/// assert_eq!(x.unwrap(), "air");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.unwrap(), "air"); // fails
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => panic!("called `Nullable::unwrap()` on a `Nullable::Null` value"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or a default.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("car").unwrap_or("bike"), "car");
|
||||
/// assert_eq!(Nullable::Null.unwrap_or("bike"), "bike");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or(self, def: T) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => def,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or computes it from a closure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let k = 10;
|
||||
/// assert_eq!(Nullable::Present(4).unwrap_or_else(|| 2 * k), 4);
|
||||
/// assert_eq!(Nullable::Null.unwrap_or_else(|| 2 * k), 20);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Transforming contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps a `Nullable<T>` to `Nullable<U>` by applying a function to a contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert a `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, consuming the original:
|
||||
///
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let maybe_some_string = Nullable::Present(String::from("Hello, World!"));
|
||||
/// // `Nullable::map` takes self *by value*, consuming `maybe_some_string`
|
||||
/// let maybe_some_len = maybe_some_string.map(|s| s.len());
|
||||
///
|
||||
/// assert_eq!(maybe_some_len, Nullable::Present(13));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => Nullable::Present(f(x)),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or returns a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or computes a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let k = 21;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err)`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or(0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or(0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err())`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err()),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Boolean operations on the values, eager and lazy
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Present("foo"));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and<U>(self, optb: Nullable<U>) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(_) => optb,
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise calls `f` with the
|
||||
/// wrapped value and returns the result.
|
||||
///
|
||||
/// Some languages call this operation flatmap.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// fn sq(x: u32) -> Nullable<u32> { Nullable::Present(x * x) }
|
||||
/// fn nope(_: u32) -> Nullable<u32> { Nullable::Null }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(sq), Nullable::Present(16));
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(nope), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Present(2).and_then(nope).and_then(sq), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Null.and_then(sq).and_then(sq), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and_then<U, F: FnOnce(T) -> Nullable<U>>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => f(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x = Nullable::Null;
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(100));
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or(self, optb: Nullable<T>) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => optb,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise calls `f` and
|
||||
/// returns the result.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// fn nobody() -> Nullable<&'static str> { Nullable::Null }
|
||||
/// fn vikings() -> Nullable<&'static str> { Nullable::Present("vikings") }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("barbarians").or_else(vikings),
|
||||
/// Nullable::Present("barbarians"));
|
||||
/// assert_eq!(Nullable::Null.or_else(vikings), Nullable::Present("vikings"));
|
||||
/// assert_eq!(Nullable::Null.or_else(nobody), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Takes the value out of the Nullable, leaving a `Nullable::Null` in its place.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
///
|
||||
/// let mut x: Nullable<u32> = Nullable::Null;
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn take(&mut self) -> Nullable<T> {
|
||||
mem::replace(self, Nullable::Null)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> Nullable<&'a T> {
|
||||
/// Maps an `Nullable<&T>` to an `Nullable<T>` by cloning the contents of the
|
||||
/// Nullable.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x = 12;
|
||||
/// let opt_x = Nullable::Present(&x);
|
||||
/// assert_eq!(opt_x, Nullable::Present(&12));
|
||||
/// let cloned = opt_x.cloned();
|
||||
/// assert_eq!(cloned, Nullable::Present(12));
|
||||
/// ```
|
||||
pub fn cloned(self) -> Nullable<T> {
|
||||
self.map(Clone::clone)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Nullable<T> {
|
||||
/// Returns the contained value or a default
|
||||
///
|
||||
/// Consumes the `self` argument then, if `Nullable::Present`, returns the contained
|
||||
/// value, otherwise if `Nullable::Null`, returns the default value for that
|
||||
/// type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use petstore::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(42);
|
||||
/// assert_eq!(42, x.unwrap_or_default());
|
||||
///
|
||||
/// let y: Nullable<i32> = Nullable::Null;
|
||||
/// assert_eq!(0, y.unwrap_or_default());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_default(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Nullable<T> {
|
||||
/// Returns None.
|
||||
#[inline]
|
||||
fn default() -> Nullable<T> {
|
||||
Nullable::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Nullable<T> {
|
||||
fn from(val: T) -> Nullable<T> {
|
||||
Nullable::Present(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Nullable<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
Nullable::Present(ref inner) => serializer.serialize_some(&inner),
|
||||
Nullable::Null => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Nullable<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Nullable<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// In order to deserialize a required, but nullable, value, we first have to check whether
|
||||
// the value is present at all. To do this, we deserialize to a serde_json::Value, which
|
||||
// fails if the value is missing, or gives serde_json::Value::Null if the value is present.
|
||||
// If that succeeds as null, we can easily return a Null.
|
||||
// If that succeeds as some value, we deserialize that value and return a Present.
|
||||
// If that errors, we return the error.
|
||||
let presence: Result<::serde_json::Value, _> =
|
||||
serde::Deserialize::deserialize(deserializer);
|
||||
match presence {
|
||||
Ok(serde_json::Value::Null) => Ok(Nullable::Null),
|
||||
Ok(some_value) => serde_json::from_value(some_value)
|
||||
.map(Nullable::Present)
|
||||
.map_err(serde::de::Error::custom),
|
||||
Err(x) => Err(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn expect_failed(msg: &str) -> ! {
|
||||
panic!("{}", msg)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
/// Base64-encoded byte array
|
||||
pub struct ByteArray(pub Vec<u8>);
|
||||
|
||||
impl Serialize for ByteArray {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&general_purpose::STANDARD.encode(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ByteArray {
|
||||
fn deserialize<D>(deserializer: D) -> Result<ByteArray, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
match general_purpose::STANDARD.decode(s) {
|
||||
Ok(bin) => Ok(ByteArray(bin)),
|
||||
_ => Err(serde::de::Error::custom("invalid base64")),
|
||||
}
|
||||
}
|
||||
}
|
2
samples/server/petstore/rust-axum/output/ping-bearer-auth/.gitignore
vendored
Normal file
2
samples/server/petstore/rust-axum/output/ping-bearer-auth/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1,8 @@
|
||||
.gitignore
|
||||
Cargo.toml
|
||||
README.md
|
||||
src/header.rs
|
||||
src/lib.rs
|
||||
src/models.rs
|
||||
src/server/mod.rs
|
||||
src/types.rs
|
@ -0,0 +1 @@
|
||||
7.3.0-SNAPSHOT
|
@ -0,0 +1,46 @@
|
||||
[package]
|
||||
name = "ping-bearer-auth"
|
||||
version = "1.0.0"
|
||||
authors = ["OpenAPI Generator team and contributors"]
|
||||
description = "No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["server"]
|
||||
server = []
|
||||
conversion = [
|
||||
"frunk",
|
||||
"frunk_derives",
|
||||
"frunk_core",
|
||||
"frunk-enum-core",
|
||||
"frunk-enum-derive",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
axum = { version = "0.7" }
|
||||
axum-extra = { version = "0.9", features = ["cookie", "multipart"] }
|
||||
base64 = "0.21"
|
||||
bytes = "1"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
frunk = { version = "0.4", optional = true }
|
||||
frunk-enum-core = { version = "0.3", optional = true }
|
||||
frunk-enum-derive = { version = "0.3", optional = true }
|
||||
frunk_core = { version = "0.4", optional = true }
|
||||
frunk_derives = { version = "0.4", optional = true }
|
||||
http = "1"
|
||||
lazy_static = "1"
|
||||
regex = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
serde_urlencoded = "0.7"
|
||||
tokio = { version = "1", default-features = false, features = [
|
||||
"signal",
|
||||
"rt-multi-thread",
|
||||
] }
|
||||
tracing = { version = "0.1", features = ["attributes"] }
|
||||
uuid = { version = "1", features = ["serde"] }
|
||||
validator = { version = "0.16", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = "0.3"
|
@ -0,0 +1,91 @@
|
||||
# Rust API for ping-bearer-auth
|
||||
|
||||
No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
|
||||
## Overview
|
||||
|
||||
This server was generated by the [openapi-generator]
|
||||
(https://openapi-generator.tech) project. By using the
|
||||
[OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
|
||||
server, you can easily generate a server stub.
|
||||
|
||||
To see how to make this your own, look here: [README]((https://openapi-generator.tech))
|
||||
|
||||
- API version: 1.0
|
||||
|
||||
|
||||
|
||||
|
||||
This autogenerated project defines an API crate `ping-bearer-auth` which contains:
|
||||
* An `Api` trait defining the API in Rust.
|
||||
* Data types representing the underlying data model.
|
||||
* Axum router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
|
||||
* Request validations (path, query, body params) are included.
|
||||
|
||||
## Using the generated library
|
||||
|
||||
The generated library has a few optional features that can be activated through Cargo.
|
||||
|
||||
* `server`
|
||||
* This defaults to enabled and creates the basic skeleton of a server implementation based on Axum.
|
||||
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
|
||||
* `conversions`
|
||||
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
|
||||
|
||||
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
|
||||
|
||||
### Example
|
||||
|
||||
```rust
|
||||
struct ServerImpl {
|
||||
// database: sea_orm::DbConn,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[async_trait]
|
||||
impl ping-bearer-auth::Api for ServerImpl {
|
||||
// API implementation goes here
|
||||
}
|
||||
|
||||
pub async fn start_server(addr: &str) {
|
||||
// initialize tracing
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// Init Axum router
|
||||
let app = ping-bearer-auth::server::new(Arc::new(ServerImpl));
|
||||
|
||||
// Add layers to the router
|
||||
let app = app.layer(...);
|
||||
|
||||
// Run the server with graceful shutdown
|
||||
let listener = TcpListener::bind(addr).await.unwrap();
|
||||
axum::serve(listener, app)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,197 @@
|
||||
use std::{convert::TryFrom, fmt, ops::Deref};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use http::HeaderValue;
|
||||
|
||||
/// A struct to allow homogeneous conversion into a HeaderValue. We can't
|
||||
/// implement the From/Into trait on HeaderValue because we don't own
|
||||
/// either of the types.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct IntoHeaderValue<T>(pub T);
|
||||
|
||||
// Generic implementations
|
||||
|
||||
impl<T> Deref for IntoHeaderValue<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
// Derive for each TryFrom<T> in http::HeaderValue
|
||||
|
||||
macro_rules! ihv_generate {
|
||||
($t:ident) => {
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<$t> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse::<$t>() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse {} as a string: {}",
|
||||
stringify!($t),
|
||||
e
|
||||
)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse header {:?} as a string - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<$t>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<$t>) -> Result<Self, Self::Error> {
|
||||
Ok(hdr_value.0.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ihv_generate!(u64);
|
||||
ihv_generate!(i64);
|
||||
ihv_generate!(i16);
|
||||
ihv_generate!(u16);
|
||||
ihv_generate!(u32);
|
||||
ihv_generate!(usize);
|
||||
ihv_generate!(isize);
|
||||
ihv_generate!(i32);
|
||||
|
||||
// Custom derivations
|
||||
|
||||
// Vec<String>
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<Vec<String>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(
|
||||
hdr_value
|
||||
.split(',')
|
||||
.filter_map(|x| match x.trim() {
|
||||
"" => None,
|
||||
y => Some(y.to_string()),
|
||||
})
|
||||
.collect(),
|
||||
)),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to parse header: {:?} as a string - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<Vec<String>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<Vec<String>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.join(", ")) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} into a header - {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<String> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())),
|
||||
Err(e) => Err(format!("Unable to convert header {:?} to {}", hdr_value, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<String>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<String>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} from a header {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bool
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<bool> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match hdr_value.parse() {
|
||||
Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)),
|
||||
Err(e) => Err(format!("Unable to parse bool from {} - {}", hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} from a header {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<bool>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<bool>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(&hdr_value.0.to_string()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert: {:?} into a header: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DateTime
|
||||
|
||||
impl TryFrom<HeaderValue> for IntoHeaderValue<DateTime<Utc>> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
|
||||
match hdr_value.to_str() {
|
||||
Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) {
|
||||
Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))),
|
||||
Err(e) => Err(format!("Unable to parse: {} as date - {}", hdr_value, e)),
|
||||
},
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert header {:?} to string {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IntoHeaderValue<DateTime<Utc>>> for HeaderValue {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(hdr_value: IntoHeaderValue<DateTime<Utc>>) -> Result<Self, Self::Error> {
|
||||
match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) {
|
||||
Ok(hdr_value) => Ok(hdr_value),
|
||||
Err(e) => Err(format!(
|
||||
"Unable to convert {:?} to a header: {}",
|
||||
hdr_value, e
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
#![allow(
|
||||
missing_docs,
|
||||
trivial_casts,
|
||||
unused_variables,
|
||||
unused_mut,
|
||||
unused_imports,
|
||||
unused_extern_crates,
|
||||
non_camel_case_types
|
||||
)]
|
||||
#![allow(unused_imports, unused_attributes)]
|
||||
#![allow(clippy::derive_partial_eq_without_eq, clippy::disallowed_names)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use axum::extract::*;
|
||||
use axum_extra::extract::{CookieJar, Multipart};
|
||||
use bytes::Bytes;
|
||||
use http::Method;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use types::*;
|
||||
|
||||
pub const BASE_PATH: &str = "";
|
||||
pub const API_VERSION: &str = "1.0";
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PingGetResponse {
|
||||
/// OK
|
||||
OK,
|
||||
}
|
||||
|
||||
/// API
|
||||
#[async_trait]
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub trait Api {
|
||||
/// PingGet - GET /ping
|
||||
async fn ping_get(
|
||||
&self,
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
) -> Result<PingGetResponse, String>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub mod server;
|
||||
|
||||
pub mod models;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub(crate) mod header;
|
@ -0,0 +1,8 @@
|
||||
#![allow(unused_qualifications)]
|
||||
|
||||
use http::HeaderValue;
|
||||
use validator::Validate;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
use crate::header;
|
||||
use crate::{models, types::*};
|
@ -0,0 +1,80 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use axum::{body::Body, extract::*, response::Response, routing::*};
|
||||
use axum_extra::extract::{CookieJar, Multipart};
|
||||
use bytes::Bytes;
|
||||
use http::{header::CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue, Method, StatusCode};
|
||||
use tracing::error;
|
||||
use validator::{Validate, ValidationErrors};
|
||||
|
||||
use crate::{header, types::*};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::models;
|
||||
|
||||
use crate::{Api, PingGetResponse};
|
||||
|
||||
/// Setup API Server.
|
||||
pub fn new<I, A>(api_impl: I) -> Router
|
||||
where
|
||||
I: AsRef<A> + Clone + Send + Sync + 'static,
|
||||
A: Api + 'static,
|
||||
{
|
||||
// build our application with a route
|
||||
Router::new()
|
||||
.route("/ping", get(ping_get::<I, A>))
|
||||
.with_state(api_impl)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn ping_get_validation() -> std::result::Result<(), ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// PingGet - GET /ping
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn ping_get<I, A>(
|
||||
method: Method,
|
||||
host: Host,
|
||||
cookies: CookieJar,
|
||||
State(api_impl): State<I>,
|
||||
) -> Result<Response, StatusCode>
|
||||
where
|
||||
I: AsRef<A> + Send + Sync,
|
||||
A: Api,
|
||||
{
|
||||
#[allow(clippy::redundant_closure)]
|
||||
let validation = tokio::task::spawn_blocking(move || ping_get_validation())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let Ok(()) = validation else {
|
||||
return Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(validation.unwrap_err().to_string()))
|
||||
.map_err(|_| StatusCode::BAD_REQUEST);
|
||||
};
|
||||
|
||||
let result = api_impl.as_ref().ping_get(method, host, cookies).await;
|
||||
|
||||
let mut response = Response::builder();
|
||||
|
||||
let resp = match result {
|
||||
Ok(rsp) => match rsp {
|
||||
PingGetResponse::OK => {
|
||||
let mut response = response.status(201);
|
||||
response.body(Body::empty())
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
// Application code returned an error. This should not happen, as the implementation should
|
||||
// return a valid response.
|
||||
response.status(500).body(Body::empty())
|
||||
}
|
||||
};
|
||||
|
||||
resp.map_err(|e| {
|
||||
error!(error = ?e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})
|
||||
}
|
@ -0,0 +1,665 @@
|
||||
use std::{mem, str::FromStr};
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Object(serde_json::Value);
|
||||
|
||||
impl validator::Validate for Object {
|
||||
fn validate(&self) -> Result<(), validator::ValidationErrors> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Object {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(serde_json::Value::String(s.to_owned())))
|
||||
}
|
||||
}
|
||||
|
||||
/// Serde helper function to create a default `Option<Nullable<T>>` while
|
||||
/// deserializing
|
||||
pub fn default_optional_nullable<T>() -> Option<Nullable<T>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Serde helper function to deserialize into an `Option<Nullable<T>>`
|
||||
pub fn deserialize_optional_nullable<'de, D, T>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<Nullable<T>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
Option::<T>::deserialize(deserializer).map(|val| match val {
|
||||
Some(inner) => Some(Nullable::Present(inner)),
|
||||
None => Some(Nullable::Null),
|
||||
})
|
||||
}
|
||||
|
||||
/// The Nullable type. Represents a value which may be specified as null on an API.
|
||||
/// Note that this is distinct from a value that is optional and not present!
|
||||
///
|
||||
/// Nullable implements many of the same methods as the Option type (map, unwrap, etc).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum Nullable<T> {
|
||||
/// Null value
|
||||
Null,
|
||||
/// Value is present
|
||||
Present(T),
|
||||
}
|
||||
|
||||
impl<T> Nullable<T> {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `true` if the Nullable is a `Present` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_present(), true);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_present(), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_present(&self) -> bool {
|
||||
match *self {
|
||||
Nullable::Present(_) => true,
|
||||
Nullable::Null => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the Nullable is a `Null` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Present(2);
|
||||
/// assert_eq!(x.is_null(), false);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// assert_eq!(x.is_null(), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_null(&self) -> bool {
|
||||
!self.is_present()
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert an `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, preserving the original.
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take a `Nullable` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: enum.Nullable.html#method.map
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let num_as_str: Nullable<String> = Nullable::Present("10".to_string());
|
||||
/// // First, cast `Nullable<String>` to `Nullable<&String>` with `as_ref`,
|
||||
/// // then consume *that* with `map`, leaving `num_as_str` on the stack.
|
||||
/// let num_as_int: Nullable<usize> = num_as_str.as_ref().map(|n| n.len());
|
||||
/// println!("still can print num_as_str: {:?}", num_as_str);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_ref(&self) -> Nullable<&T> {
|
||||
match *self {
|
||||
Nullable::Present(ref x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `Nullable<T>` to `Nullable<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// match x.as_mut() {
|
||||
/// Nullable::Present(v) => *v = 42,
|
||||
/// Nullable::Null => {},
|
||||
/// }
|
||||
/// assert_eq!(x, Nullable::Present(42));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut(&mut self) -> Nullable<&mut T> {
|
||||
match *self {
|
||||
Nullable::Present(ref mut x) => Nullable::Present(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Getting to contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Unwraps a Nullable, yielding the content of a `Nullable::Present`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is a [`Nullable::Null`] with a custom panic message provided by
|
||||
/// `msg`.
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("value");
|
||||
/// assert_eq!(x.expect("the world is ending"), "value");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// x.expect("the world is ending"); // panics with `the world is ending`
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn expect(self, msg: &str) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => expect_failed(msg),
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves the value `v` out of the `Nullable<T>` if it is `Nullable::Present(v)`.
|
||||
///
|
||||
/// In general, because this function may panic, its use is discouraged.
|
||||
/// Instead, prefer to use pattern matching and handle the `Nullable::Null`
|
||||
/// case explicitly.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the self value equals [`Nullable::Null`].
|
||||
///
|
||||
/// [`Nullable::Null`]: #variant.Null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("air");
|
||||
/// assert_eq!(x.unwrap(), "air");
|
||||
/// ```
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.unwrap(), "air"); // fails
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(val) => val,
|
||||
Nullable::Null => panic!("called `Nullable::unwrap()` on a `Nullable::Null` value"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or a default.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("car").unwrap_or("bike"), "car");
|
||||
/// assert_eq!(Nullable::Null.unwrap_or("bike"), "bike");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or(self, def: T) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => def,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or computes it from a closure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let k = 10;
|
||||
/// assert_eq!(Nullable::Present(4).unwrap_or_else(|| 2 * k), 4);
|
||||
/// assert_eq!(Nullable::Null.unwrap_or_else(|| 2 * k), 20);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Transforming contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps a `Nullable<T>` to `Nullable<U>` by applying a function to a contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert a `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, consuming the original:
|
||||
///
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let maybe_some_string = Nullable::Present(String::from("Hello, World!"));
|
||||
/// // `Nullable::map` takes self *by value*, consuming `maybe_some_string`
|
||||
/// let maybe_some_len = maybe_some_string.map(|s| s.len());
|
||||
///
|
||||
/// assert_eq!(maybe_some_len, Nullable::Present(13));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => Nullable::Present(f(x)),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or returns a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or computes a `default` (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let k = 21;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
|
||||
match self {
|
||||
Nullable::Present(t) => f(t),
|
||||
Nullable::Null => default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err)`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or(0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or(0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
|
||||
/// [`Ok(v)`] and `Nullable::Null` to [`Err(err())`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present("foo");
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
|
||||
///
|
||||
/// let x: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
|
||||
match self {
|
||||
Nullable::Present(v) => Ok(v),
|
||||
Nullable::Null => Err(err()),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Boolean operations on the values, eager and lazy
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present("foo");
|
||||
/// assert_eq!(x.and(y), Nullable::Present("foo"));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y: Nullable<&str> = Nullable::Null;
|
||||
/// assert_eq!(x.and(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and<U>(self, optb: Nullable<U>) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(_) => optb,
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise calls `f` with the
|
||||
/// wrapped value and returns the result.
|
||||
///
|
||||
/// Some languages call this operation flatmap.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// fn sq(x: u32) -> Nullable<u32> { Nullable::Present(x * x) }
|
||||
/// fn nope(_: u32) -> Nullable<u32> { Nullable::Null }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(sq), Nullable::Present(16));
|
||||
/// assert_eq!(Nullable::Present(2).and_then(sq).and_then(nope), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Present(2).and_then(nope).and_then(sq), Nullable::Null);
|
||||
/// assert_eq!(Nullable::Null.and_then(sq).and_then(sq), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and_then<U, F: FnOnce(T) -> Nullable<U>>(self, f: F) -> Nullable<U> {
|
||||
match self {
|
||||
Nullable::Present(x) => f(x),
|
||||
Nullable::Null => Nullable::Null,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x = Nullable::Null;
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(100));
|
||||
///
|
||||
/// let x = Nullable::Present(2);
|
||||
/// let y = Nullable::Present(100);
|
||||
/// assert_eq!(x.or(y), Nullable::Present(2));
|
||||
///
|
||||
/// let x: Nullable<u32> = Nullable::Null;
|
||||
/// let y = Nullable::Null;
|
||||
/// assert_eq!(x.or(y), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or(self, optb: Nullable<T>) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => optb,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Nullable if it contains a value, otherwise calls `f` and
|
||||
/// returns the result.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// fn nobody() -> Nullable<&'static str> { Nullable::Null }
|
||||
/// fn vikings() -> Nullable<&'static str> { Nullable::Present("vikings") }
|
||||
///
|
||||
/// assert_eq!(Nullable::Present("barbarians").or_else(vikings),
|
||||
/// Nullable::Present("barbarians"));
|
||||
/// assert_eq!(Nullable::Null.or_else(vikings), Nullable::Present("vikings"));
|
||||
/// assert_eq!(Nullable::Null.or_else(nobody), Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
|
||||
match self {
|
||||
Nullable::Present(_) => self,
|
||||
Nullable::Null => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Takes the value out of the Nullable, leaving a `Nullable::Null` in its place.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let mut x = Nullable::Present(2);
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
///
|
||||
/// let mut x: Nullable<u32> = Nullable::Null;
|
||||
/// x.take();
|
||||
/// assert_eq!(x, Nullable::Null);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn take(&mut self) -> Nullable<T> {
|
||||
mem::replace(self, Nullable::Null)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> Nullable<&'a T> {
|
||||
/// Maps an `Nullable<&T>` to an `Nullable<T>` by cloning the contents of the
|
||||
/// Nullable.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x = 12;
|
||||
/// let opt_x = Nullable::Present(&x);
|
||||
/// assert_eq!(opt_x, Nullable::Present(&12));
|
||||
/// let cloned = opt_x.cloned();
|
||||
/// assert_eq!(cloned, Nullable::Present(12));
|
||||
/// ```
|
||||
pub fn cloned(self) -> Nullable<T> {
|
||||
self.map(Clone::clone)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Nullable<T> {
|
||||
/// Returns the contained value or a default
|
||||
///
|
||||
/// Consumes the `self` argument then, if `Nullable::Present`, returns the contained
|
||||
/// value, otherwise if `Nullable::Null`, returns the default value for that
|
||||
/// type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ping_bearer_auth::types::Nullable;
|
||||
///
|
||||
/// let x = Nullable::Present(42);
|
||||
/// assert_eq!(42, x.unwrap_or_default());
|
||||
///
|
||||
/// let y: Nullable<i32> = Nullable::Null;
|
||||
/// assert_eq!(0, y.unwrap_or_default());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_default(self) -> T {
|
||||
match self {
|
||||
Nullable::Present(x) => x,
|
||||
Nullable::Null => Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Nullable<T> {
|
||||
/// Returns None.
|
||||
#[inline]
|
||||
fn default() -> Nullable<T> {
|
||||
Nullable::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Nullable<T> {
|
||||
fn from(val: T) -> Nullable<T> {
|
||||
Nullable::Present(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Nullable<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
Nullable::Present(ref inner) => serializer.serialize_some(&inner),
|
||||
Nullable::Null => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Nullable<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Nullable<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// In order to deserialize a required, but nullable, value, we first have to check whether
|
||||
// the value is present at all. To do this, we deserialize to a serde_json::Value, which
|
||||
// fails if the value is missing, or gives serde_json::Value::Null if the value is present.
|
||||
// If that succeeds as null, we can easily return a Null.
|
||||
// If that succeeds as some value, we deserialize that value and return a Present.
|
||||
// If that errors, we return the error.
|
||||
let presence: Result<::serde_json::Value, _> =
|
||||
serde::Deserialize::deserialize(deserializer);
|
||||
match presence {
|
||||
Ok(serde_json::Value::Null) => Ok(Nullable::Null),
|
||||
Ok(some_value) => serde_json::from_value(some_value)
|
||||
.map(Nullable::Present)
|
||||
.map_err(serde::de::Error::custom),
|
||||
Err(x) => Err(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn expect_failed(msg: &str) -> ! {
|
||||
panic!("{}", msg)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
/// Base64-encoded byte array
|
||||
pub struct ByteArray(pub Vec<u8>);
|
||||
|
||||
impl Serialize for ByteArray {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&general_purpose::STANDARD.encode(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ByteArray {
|
||||
fn deserialize<D>(deserializer: D) -> Result<ByteArray, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
match general_purpose::STANDARD.decode(s) {
|
||||
Ok(bin) => Ok(ByteArray(bin)),
|
||||
_ => Err(serde::de::Error::custom("invalid base64")),
|
||||
}
|
||||
}
|
||||
}
|
2
samples/server/petstore/rust-axum/output/rust-axum-test/.gitignore
vendored
Normal file
2
samples/server/petstore/rust-axum/output/rust-axum-test/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1,8 @@
|
||||
.gitignore
|
||||
Cargo.toml
|
||||
README.md
|
||||
src/header.rs
|
||||
src/lib.rs
|
||||
src/models.rs
|
||||
src/server/mod.rs
|
||||
src/types.rs
|
@ -0,0 +1 @@
|
||||
7.3.0-SNAPSHOT
|
@ -0,0 +1,46 @@
|
||||
[package]
|
||||
name = "rust-server-test"
|
||||
version = "2.3.4"
|
||||
authors = ["OpenAPI Generator team and contributors"]
|
||||
description = "This spec is for testing rust-server-specific things"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["server"]
|
||||
server = []
|
||||
conversion = [
|
||||
"frunk",
|
||||
"frunk_derives",
|
||||
"frunk_core",
|
||||
"frunk-enum-core",
|
||||
"frunk-enum-derive",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
axum = { version = "0.7" }
|
||||
axum-extra = { version = "0.9", features = ["cookie", "multipart"] }
|
||||
base64 = "0.21"
|
||||
bytes = "1"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
frunk = { version = "0.4", optional = true }
|
||||
frunk-enum-core = { version = "0.3", optional = true }
|
||||
frunk-enum-derive = { version = "0.3", optional = true }
|
||||
frunk_core = { version = "0.4", optional = true }
|
||||
frunk_derives = { version = "0.4", optional = true }
|
||||
http = "1"
|
||||
lazy_static = "1"
|
||||
regex = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
serde_urlencoded = "0.7"
|
||||
tokio = { version = "1", default-features = false, features = [
|
||||
"signal",
|
||||
"rt-multi-thread",
|
||||
] }
|
||||
tracing = { version = "0.1", features = ["attributes"] }
|
||||
uuid = { version = "1", features = ["serde"] }
|
||||
validator = { version = "0.16", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = "0.3"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user