diff --git a/core/Cargo.toml b/core/Cargo.toml index e007e225b..3ae100bf2 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -17,7 +17,7 @@ chrono = { version = "0", optional = true } heck = { version = "0.3", optional = true } lazy_static = "1.3" log = { version = "0.4", optional = true } -mime = { git = "https://github.com/hyperium/mime", rev = "938484de95445a2af931515d2b7252612c575da7", features = ["serde1"] } +mime = "0.3" paperclip-macros = { path = "../macros", version = "0.3.0" } parking_lot = { version = "0.10", features = ["serde"] } rust_decimal = { version = "1", optional = true } diff --git a/core/src/v2/extensions.rs b/core/src/v2/extensions.rs index d87468c56..988fc7d9e 100644 --- a/core/src/v2/extensions.rs +++ b/core/src/v2/extensions.rs @@ -3,13 +3,14 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::cmp::Ordering; use std::collections::BTreeMap; +use std::fmt; use std::ops::{Deref, DerefMut}; use std::sync::Arc; lazy_static! { /// Media range for JSON. pub static ref JSON_MIME: MediaRange = - MediaRange(mime::MediaRange::parse("application/json").expect("parsing mime")); + MediaRange("application/json".parse().expect("parsing mime")); /// Default coder for JSON. pub static ref JSON_CODER: Arc = Arc::new(Coder { encoder_path: "serde_json::to_writer".into(), @@ -21,7 +22,7 @@ lazy_static! { }); /// Media range for YAML. pub static ref YAML_MIME: MediaRange = - MediaRange(mime::MediaRange::parse("application/yaml").expect("parsing mime")); + MediaRange("application/yaml".parse().expect("parsing mime")); /// Default coder for YAML. pub static ref YAML_CODER: Arc = Arc::new(Coder { encoder_path: "serde_yaml::to_writer".into(), @@ -35,14 +36,14 @@ lazy_static! { /// Wrapper for `mime::MediaRange` to support `BTree{Set, Map}`. #[derive(Debug, Clone)] -pub struct MediaRange(pub mime::MediaRange); +pub struct MediaRange(pub mime::Mime); #[cfg(feature = "codegen")] impl MediaRange { /// Implementation from https://github.com/hyperium/mime/blob/65ea9c3d0cad4cb548b41124050c545120134035/src/range.rs#L155 fn matches_params(&self, r: &Self) -> bool { for (name, value) in self.0.params() { - if name != "q" && r.0.param(name) != Some(value) { + if name != "q" && r.0.get_param(name) != Some(value) { return false; } } @@ -51,7 +52,7 @@ impl MediaRange { } } -/// `x-coder` global extension for custom encoders and decoders. +/// `x-rust-coders` global extension for custom encoders and decoders. #[derive(Debug, Default, Clone)] pub struct Coders(BTreeMap>); @@ -140,7 +141,7 @@ impl Serialize for MediaRange { where S: Serializer, { - self.0.serialize(serializer) + serializer.serialize_str(self.0.as_ref()) } } @@ -149,7 +150,24 @@ impl<'de> Deserialize<'de> for MediaRange { where D: Deserializer<'de>, { - Ok(MediaRange(mime::MediaRange::deserialize(deserializer)?)) + struct Visitor; + + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = MediaRange; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("a valid media range") + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + value.parse().map_err(E::custom).map(MediaRange) + } + } + + deserializer.deserialize_str(Visitor) } } diff --git a/core/src/v2/models.rs b/core/src/v2/models.rs index 34aa06c38..3ce84775b 100644 --- a/core/src/v2/models.rs +++ b/core/src/v2/models.rs @@ -119,6 +119,18 @@ pub struct Api { pub tags: Vec, #[serde(rename = "externalDocs", skip_serializing_if = "Option::is_none")] pub external_docs: Option, + /// Extension for custom coders to be used for decoding API objects. + /// + /// An example for JSON would be: + /// ```yaml + /// x-rust-coders: + /// application/json: + /// encoder_path: serde_json::to_writer + /// decoder_path: serde_json::from_reader + /// any_value: serde_json::Value + /// error_path: serde_json::Error + /// ``` + /// **NOTE:** JSON and YAML encodings are already supported. #[serde( default, rename = "x-rust-coders", @@ -129,13 +141,13 @@ pub struct Api { /// /// The key is the LHS of a dependency, which is the crate name. /// The value is the RHS of a crate's requirements as it would appear - /// in the manifest. Note that the caller must add proper quoting - /// whenever required. + /// in the manifest. Note that the caller must add proper escaping + /// wherever required. /// - /// For example, in a JSON spec, the following are all valid: - /// - `{"my_crate": "0.7"}` - /// - `{"my_crate": "{ git = \"git://foo.bar/repo\" }"}` - /// - `{"my_crate": "{ version = \"0.9\", features = [\"booya\"] }"}` + /// For example, the following are all valid: + /// - `my_crate: "0.7"` + /// - `my_crate: "{ git = \"git://foo.bar/repo\" }"` + /// - `my_crate: "{ version = \"0.9\", features = [\"booya\"] }"` #[serde( default, rename = "x-rust-dependencies",