mirror of
https://github.com/poem-web/poem.git
synced 2026-01-25 04:18:25 +00:00
add support for camino::Utf8PathBuf and camino::Utf8Path (#1103)
This commit is contained in:
@@ -27,6 +27,7 @@ websocket = ["poem/websocket"]
|
||||
geo = ["dep:geo-types", "dep:geojson"]
|
||||
sonic-rs = ["poem/sonic-rs"]
|
||||
cookie = ["poem/cookie"]
|
||||
camino = ["dep:camino"]
|
||||
ulid = ["dep:ulid"]
|
||||
|
||||
[dependencies]
|
||||
@@ -84,6 +85,7 @@ sqlx = { version = "0.8.3", features = [
|
||||
"sqlite",
|
||||
"mysql",
|
||||
], optional = true }
|
||||
camino = { version = "1.2.1", optional = true }
|
||||
ulid = { version = "1.2.1", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -52,6 +52,7 @@ To avoid compiling unused dependencies, Poem gates certain features, some of whi
|
||||
|
||||
| Feature | Description |
|
||||
|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| camino | Integrate with the [`camino` crate](https://crates.io/crates/camino). |
|
||||
| chrono | Integrate with the [`chrono` crate](https://crates.io/crates/chrono). |
|
||||
| time | Integrate with the [`time` crate](https://crates.io/crates/time). |
|
||||
| humantime | Integrate with the [`humantime` crate](https://crates.io/crates/humantime) |
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
//!
|
||||
//! | Feature | Description |
|
||||
//! |--------------------|----------------------------------------------------------------------------------------|
|
||||
//! | camino | Integrate with the [`camino` crate](https://crates.io/crates/camino). |
|
||||
//! | chrono | Integrate with the [`chrono` crate](https://crates.io/crates/chrono). |
|
||||
//! | time | Integrate with the [`time` crate](https://crates.io/crates/time). |
|
||||
//! | humantime | Integrate with the [`humantime` crate](https://crates.io/crates/humantime) |
|
||||
|
||||
189
poem-openapi/src/types/external/camino.rs
vendored
Normal file
189
poem-openapi/src/types/external/camino.rs
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use poem::{http::HeaderValue, web::Field};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
registry::{MetaSchema, MetaSchemaRef},
|
||||
types::{
|
||||
ParseError, ParseFromJSON, ParseFromMultipartField, ParseFromParameter, ParseResult,
|
||||
ToHeader, ToJSON, Type,
|
||||
},
|
||||
};
|
||||
|
||||
impl Type for Utf8PathBuf {
|
||||
const IS_REQUIRED: bool = true;
|
||||
|
||||
type RawValueType = Self;
|
||||
|
||||
type RawElementValueType = Self;
|
||||
|
||||
fn name() -> Cow<'static, str> {
|
||||
"path".into()
|
||||
}
|
||||
|
||||
fn schema_ref() -> MetaSchemaRef {
|
||||
MetaSchemaRef::Inline(Box::new(MetaSchema::new_with_format("string", "path")))
|
||||
}
|
||||
|
||||
fn as_raw_value(&self) -> Option<&Self::RawValueType> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn raw_element_iter<'a>(
|
||||
&'a self,
|
||||
) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
|
||||
Box::new(self.as_raw_value().into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseFromJSON for Utf8PathBuf {
|
||||
fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
|
||||
let value = value.unwrap_or_default();
|
||||
if let Value::String(value) = value {
|
||||
Ok(value.into())
|
||||
} else {
|
||||
Err(ParseError::expected_type(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseFromParameter for Utf8PathBuf {
|
||||
fn parse_from_parameter(value: &str) -> ParseResult<Self> {
|
||||
Ok(Utf8Path::new(value).to_path_buf())
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseFromMultipartField for Utf8PathBuf {
|
||||
async fn parse_from_multipart(field: Option<Field>) -> ParseResult<Self> {
|
||||
match field {
|
||||
Some(field) => Ok(field.text().await?.into()),
|
||||
None => Err(ParseError::expected_input()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJSON for Utf8PathBuf {
|
||||
fn to_json(&self) -> Option<Value> {
|
||||
Some(Value::String(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHeader for Utf8PathBuf {
|
||||
fn to_header(&self) -> Option<HeaderValue> {
|
||||
HeaderValue::from_str(self.as_str()).ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl Type for &Utf8Path {
|
||||
const IS_REQUIRED: bool = true;
|
||||
|
||||
type RawValueType = Self;
|
||||
|
||||
type RawElementValueType = Self;
|
||||
|
||||
fn name() -> Cow<'static, str> {
|
||||
"path".into()
|
||||
}
|
||||
|
||||
fn schema_ref() -> MetaSchemaRef {
|
||||
MetaSchemaRef::Inline(Box::new(MetaSchema::new_with_format("string", "path")))
|
||||
}
|
||||
|
||||
fn as_raw_value(&self) -> Option<&Self::RawValueType> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn raw_element_iter<'a>(
|
||||
&'a self,
|
||||
) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
|
||||
Box::new(self.as_raw_value().into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJSON for &Utf8Path {
|
||||
fn to_json(&self) -> Option<Value> {
|
||||
Some(Value::String(self.as_str().to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHeader for &Utf8Path {
|
||||
fn to_header(&self) -> Option<HeaderValue> {
|
||||
HeaderValue::from_str(self.as_str()).ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn type_name() {
|
||||
assert_eq!(Utf8PathBuf::name(), "path");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_from_json_none() {
|
||||
assert_eq!(
|
||||
Utf8PathBuf::parse_from_json(None)
|
||||
.expect_err("unexpectedly succeeded in parsing `None`")
|
||||
.message(),
|
||||
ParseError::<Utf8PathBuf>::expected_type(Value::Null).message()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_from_json_value_null() {
|
||||
assert_eq!(
|
||||
Utf8PathBuf::parse_from_json(Some(Value::Null))
|
||||
.expect_err("unexpectedly succeeded in parsing `Value::Null`")
|
||||
.message(),
|
||||
ParseError::<Utf8PathBuf>::expected_type(Value::Null).message()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_from_json_value_string() {
|
||||
assert_eq!(
|
||||
Utf8PathBuf::parse_from_json(Some(Value::String("/a/b/c".to_owned())))
|
||||
.expect(r#"failed to parse "/a/b/c""#),
|
||||
Utf8Path::new("/a/b/c")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_from_parameter() {
|
||||
assert_eq!(
|
||||
Utf8PathBuf::parse_from_parameter("/a/b/c").expect(r#"failed to parse "/a/b/c""#),
|
||||
Utf8Path::new("/a/b/c")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn parse_from_multipart_none() {
|
||||
assert_eq!(
|
||||
Utf8PathBuf::parse_from_multipart(None)
|
||||
.await
|
||||
.expect_err("unexpectedly succeeded in parsing `None`")
|
||||
.message(),
|
||||
ParseError::<Utf8PathBuf>::expected_input().message(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_json() {
|
||||
assert_eq!(
|
||||
Utf8Path::new("/a/b/c").to_json(),
|
||||
Some(Value::String("/a/b/c".to_owned()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_header() {
|
||||
assert_eq!(
|
||||
Utf8Path::new("/a/b/c").to_header(),
|
||||
HeaderValue::from_str("/a/b/c").ok()
|
||||
);
|
||||
}
|
||||
}
|
||||
2
poem-openapi/src/types/external/mod.rs
vendored
2
poem-openapi/src/types/external/mod.rs
vendored
@@ -4,6 +4,8 @@ mod bool;
|
||||
mod bson;
|
||||
mod btreemap;
|
||||
mod btreeset;
|
||||
#[cfg(feature = "camino")]
|
||||
mod camino;
|
||||
mod char;
|
||||
#[cfg(feature = "chrono")]
|
||||
mod chrono;
|
||||
|
||||
Reference in New Issue
Block a user