From 3ab6749e7af782f3afa7731d467c8cc1ad7451af Mon Sep 17 00:00:00 2001 From: Joonas Bergius Date: Thu, 28 Nov 2024 11:06:09 -0600 Subject: [PATCH] chore: Bring types from http-types into typespec Signed-off-by: Joonas Bergius --- sdk/typespec/Cargo.toml | 7 +- sdk/typespec/src/error/mod.rs | 2 +- sdk/typespec/src/lib.rs | 10 + sdk/typespec/src/method.rs | 623 ++++++++++++++ sdk/typespec/src/status_code.rs | 758 ++++++++++++++++++ sdk/typespec/typespec_client_core/Cargo.toml | 3 +- .../typespec_client_core/src/http/mod.rs | 2 +- .../typespec_client_core/src/http/response.rs | 12 +- 8 files changed, 1404 insertions(+), 13 deletions(-) create mode 100644 sdk/typespec/src/method.rs create mode 100644 sdk/typespec/src/status_code.rs diff --git a/sdk/typespec/Cargo.toml b/sdk/typespec/Cargo.toml index 6f2f426d8b..7f10ee59ae 100644 --- a/sdk/typespec/Cargo.toml +++ b/sdk/typespec/Cargo.toml @@ -13,14 +13,15 @@ keywords = ["typespec"] [dependencies] base64.workspace = true -http-types = { workspace = true, optional = true } +serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } url.workspace = true [dev-dependencies] thiserror.workspace = true +serde_json.workspace = true [features] default = ["http", "json"] -http = ["dep:http-types"] -json = ["dep:serde_json"] +http = [] +json = ["dep:serde", "dep:serde_json"] diff --git a/sdk/typespec/src/error/mod.rs b/sdk/typespec/src/error/mod.rs index 8d5213372c..825d18e5e6 100644 --- a/sdk/typespec/src/error/mod.rs +++ b/sdk/typespec/src/error/mod.rs @@ -4,7 +4,7 @@ //! Interfaces for working with errors. #[cfg(feature = "http")] -use http_types::StatusCode; +use crate::StatusCode; use std::borrow::Cow; use std::fmt::{Debug, Display}; diff --git a/sdk/typespec/src/lib.rs b/sdk/typespec/src/lib.rs index 17d0489915..a76c5045fd 100644 --- a/sdk/typespec/src/lib.rs +++ b/sdk/typespec/src/lib.rs @@ -6,3 +6,13 @@ pub mod error; pub use error::{Error, Result}; + +#[cfg(feature = "http")] +mod method; +#[cfg(feature = "http")] +pub use crate::method::Method; + +#[cfg(feature = "http")] +mod status_code; +#[cfg(feature = "http")] +pub use crate::status_code::StatusCode; diff --git a/sdk/typespec/src/method.rs b/sdk/typespec/src/method.rs new file mode 100644 index 0000000000..35414e3fc1 --- /dev/null +++ b/sdk/typespec/src/method.rs @@ -0,0 +1,623 @@ +// Source: https://github.com/http-rs/http-types/blob/v2.12.0/src/method.rs +// InvalidMethod source: https://github.com/hyperium/http/blob/v1.1.0/src/method.rs +use std::error::Error; +use std::fmt::{self, Debug, Display}; +use std::str::FromStr; + +/// HTTP request methods. +/// +/// See also [Mozilla's documentation][Mozilla docs], the [RFC7231, Section 4][] and +/// [IANA's Hypertext Transfer Protocol (HTTP) Method Registry][HTTP Method Registry]. +/// +/// [Mozilla docs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods +/// [RFC7231, Section 4]: https://tools.ietf.org/html/rfc7231#section-4 +/// [HTTP Method Registry]: https://www.iana.org/assignments/http-methods/http-methods.xhtml +#[non_exhaustive] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub enum Method { + /// The ACL method modifies the access control list (which can be read via the DAV:acl + /// property) of a resource. + /// + /// See [RFC3744, Section 8.1][]. + /// + /// [RFC3744, Section 8.1]: https://tools.ietf.org/html/rfc3744#section-8.1 + Acl, + + /// A collection can be placed under baseline control with a BASELINE-CONTROL request. + /// + /// See [RFC3253, Section 12.6][]. + /// + /// [RFC3253, Section 12.6]: https://tools.ietf.org/html/rfc3253#section-12.6 + BaselineControl, + + /// The BIND method modifies the collection identified by the Request- URI, by adding a new + /// binding from the segment specified in the BIND body to the resource identified in the BIND + /// body. + /// + /// See [RFC5842, Section 4][]. + /// + /// [RFC5842, Section 4]: https://tools.ietf.org/html/rfc5842#section-4 + Bind, + + /// A CHECKIN request can be applied to a checked-out version-controlled resource to produce a + /// new version whose content and dead properties are copied from the checked-out resource. + /// + /// See [RFC3253, Section 4.4][] and [RFC3253, Section 9.4][]. + /// + /// [RFC3253, Section 4.4]: https://tools.ietf.org/html/rfc3253#section-4.4 + /// [RFC3253, Section 9.4]: https://tools.ietf.org/html/rfc3253#section-9.4 + Checkin, + + /// A CHECKOUT request can be applied to a checked-in version-controlled resource to allow + /// modifications to the content and dead properties of that version-controlled resource. + /// + /// See [RFC3253, Section 4.3][] and [RFC3253, Section 8.8][]. + /// + /// [RFC3253, Section 4.3]: https://tools.ietf.org/html/rfc3253#section-4.3 + /// [RFC3253, Section 8.8]: https://tools.ietf.org/html/rfc3253#section-8.8 + Checkout, + + /// The CONNECT method requests that the recipient establish a tunnel to the destination origin + /// server identified by the request-target and, if successful, thereafter restrict its + /// behavior to blind forwarding of packets, in both directions, until the tunnel is closed. + /// + /// See [RFC7231, Section 4.3.6][]. + /// + /// [RFC7231, Section 4.3.6]: https://tools.ietf.org/html/rfc7231#section-4.3.6 + Connect, + + /// The COPY method creates a duplicate of the source resource identified by the Request-URI, + /// in the destination resource identified by the URI in the Destination header. + /// + /// See [RFC4918, Section 9.8][]. + /// + /// [RFC4918, Section 9.8]: https://tools.ietf.org/html/rfc4918#section-9.8 + Copy, + + /// The DELETE method requests that the origin server remove the association between the target + /// resource and its current functionality. + /// + /// See [RFC7231, Section 4.3.5][]. + /// + /// [RFC7231, Section 4.3.5]: https://tools.ietf.org/html/rfc7231#section-4.3.5 + Delete, + + /// The GET method requests transfer of a current selected representation for the target + /// resource. + /// + /// See [RFC7231, Section 4.3.1][]. + /// + /// [RFC7231, Section 4.3.1]: https://tools.ietf.org/html/rfc7231#section-4.3.1 + Get, + + /// The HEAD method is identical to GET except that the server MUST NOT send a message body in + /// the response. + /// + /// See [RFC7231, Section 4.3.2][]. + /// + /// [RFC7231, Section 4.3.2]: https://tools.ietf.org/html/rfc7231#section-4.3.2 + Head, + + /// A LABEL request can be applied to a version to modify the labels that select that version. + /// + /// See [RFC3253, Section 8.2][]. + /// + /// [RFC3253, Section 8.2]: https://tools.ietf.org/html/rfc3253#section-8.2 + Label, + + /// The LINK method establishes one or more Link relationships between the existing resource + /// identified by the Request-URI and other existing resources. + /// + /// See [RFC2068, Section 19.6.1.2][]. + /// + /// [RFC2068, Section 19.6.1.2]: https://tools.ietf.org/html/rfc2068#section-19.6.1.2 + Link, + + /// The LOCK method is used to take out a lock of any access type and to refresh an existing + /// lock. + /// + /// See [RFC4918, Section 9.10][]. + /// + /// [RFC4918, Section 9.10]: https://tools.ietf.org/html/rfc4918#section-9.10 + Lock, + + /// The MERGE method performs the logical merge of a specified version (the "merge source") + /// into a specified version-controlled resource (the "merge target"). + /// + /// See [RFC3253, Section 11.2][]. + /// + /// [RFC3253, Section 11.2]: https://tools.ietf.org/html/rfc3253#section-11.2 + Merge, + + /// A MKACTIVITY request creates a new activity resource. + /// + /// See [RFC3253, Section 13.5]. + /// + /// [RFC3253, Section 13.5]: https://tools.ietf.org/html/rfc3253#section-13.5 + MkActivity, + + /// An HTTP request using the MKCALENDAR method creates a new calendar collection resource. + /// + /// See [RFC4791, Section 5.3.1][] and [RFC8144, Section 2.3][]. + /// + /// [RFC4791, Section 5.3.1]: https://tools.ietf.org/html/rfc4791#section-5.3.1 + /// [RFC8144, Section 2.3]: https://tools.ietf.org/html/rfc8144#section-2.3 + MkCalendar, + + /// MKCOL creates a new collection resource at the location specified by the Request-URI. + /// + /// See [RFC4918, Section 9.3][], [RFC5689, Section 3][] and [RFC8144, Section 2.3][]. + /// + /// [RFC4918, Section 9.3]: https://tools.ietf.org/html/rfc4918#section-9.3 + /// [RFC5689, Section 3]: https://tools.ietf.org/html/rfc5689#section-3 + /// [RFC8144, Section 2.3]: https://tools.ietf.org/html/rfc5689#section-3 + MkCol, + + /// The MKREDIRECTREF method requests the creation of a redirect reference resource. + /// + /// See [RFC4437, Section 6][]. + /// + /// [RFC4437, Section 6]: https://tools.ietf.org/html/rfc4437#section-6 + MkRedirectRef, + + /// A MKWORKSPACE request creates a new workspace resource. + /// + /// See [RFC3253, Section 6.3][]. + /// + /// [RFC3253, Section 6.3]: https://tools.ietf.org/html/rfc3253#section-6.3 + MkWorkspace, + + /// The MOVE operation on a non-collection resource is the logical equivalent of a copy (COPY), + /// followed by consistency maintenance processing, followed by a delete of the source, where + /// all three actions are performed in a single operation. + /// + /// See [RFC4918, Section 9.9][]. + /// + /// [RFC4918, Section 9.9]: https://tools.ietf.org/html/rfc4918#section-9.9 + Move, + + /// The OPTIONS method requests information about the communication options available for the + /// target resource, at either the origin server or an intervening intermediary. + /// + /// See [RFC7231, Section 4.3.7][]. + /// + /// [RFC7231, Section 4.3.7]: https://tools.ietf.org/html/rfc7231#section-4.3.7 + Options, + + /// The ORDERPATCH method is used to change the ordering semantics of a collection, to change + /// the order of the collection's members in the ordering, or both. + /// + /// See [RFC3648, Section 7][]. + /// + /// [RFC3648, Section 7]: https://tools.ietf.org/html/rfc3648#section-7 + OrderPatch, + + /// The PATCH method requests that a set of changes described in the request entity be applied + /// to the resource identified by the Request- URI. + /// + /// See [RFC5789, Section 2][]. + /// + /// [RFC5789, Section 2]: https://tools.ietf.org/html/rfc5789#section-2 + Patch, + + /// The POST method requests that the target resource process the representation enclosed in + /// the request according to the resource's own specific semantics. + /// + /// For example, POST is used for the following functions (among others): + /// + /// - Providing a block of data, such as the fields entered into an HTML form, to a + /// data-handling process; + /// - Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group + /// of articles; + /// - Creating a new resource that has yet to be identified by the origin server; and + /// - Appending data to a resource's existing representation(s). + /// + /// See [RFC7231, Section 4.3.3][]. + /// + /// [RFC7231, Section 4.3.3]: https://tools.ietf.org/html/rfc7231#section-4.3.3 + Post, + + /// This method is never used by an actual client. This method will appear to be used when an + /// HTTP/1.1 server or intermediary attempts to parse an HTTP/2 connection preface. + /// + /// See [RFC7540, Section 3.5][] and [RFC7540, Section 11.6][] + /// + /// [RFC7540, Section 3.5]: https://tools.ietf.org/html/rfc7540#section-3.5 + /// [RFC7540, Section 11.6]: https://tools.ietf.org/html/rfc7540#section-11.6 + Pri, + + /// The PROPFIND method retrieves properties defined on the resource identified by the + /// Request-URI. + /// + /// See [RFC4918, Section 9.1][] and [RFC8144, Section 2.1][]. + /// + /// [RFC4918, Section 9.1]: https://tools.ietf.org/html/rfc4918#section-9.1 + /// [RFC8144, Section 2.1]: https://tools.ietf.org/html/rfc8144#section-2.1 + PropFind, + + /// The PROPPATCH method processes instructions specified in the request body to set and/or + /// remove properties defined on the resource identified by the Request-URI. + /// + /// See [RFC4918, Section 9.2][] and [RFC8144, Section 2.2][]. + /// + /// [RFC4918, Section 9.2]: https://tools.ietf.org/html/rfc4918#section-9.2 + /// [RFC8144, Section 2.2]: https://tools.ietf.org/html/rfc8144#section-2.2 + PropPatch, + + /// The PUT method requests that the state of the target resource be created or replaced with + /// the state defined by the representation enclosed in the request message payload. + /// + /// See [RFC7231, Section 4.3.4][]. + /// + /// [RFC7231, Section 4.3.4]: https://tools.ietf.org/html/rfc7231#section-4.3.4 + Put, + + /// The REBIND method removes a binding to a resource from a collection, and adds a binding to + /// that resource into the collection identified by the Request-URI. + /// + /// See [RFC5842, Section 6][]. + /// + /// [RFC5842, Section 6]: https://tools.ietf.org/html/rfc5842#section-6 + Rebind, + + /// A REPORT request is an extensible mechanism for obtaining information about a resource. + /// + /// See [RFC3253, Section 3.6][] and [RFC8144, Section 2.1][]. + /// + /// [RFC3253, Section 3.6]: https://tools.ietf.org/html/rfc3253#section-3.6 + /// [RFC8144, Section 2.1]: https://tools.ietf.org/html/rfc8144#section-2.1 + Report, + + /// The client invokes the SEARCH method to initiate a server-side search. The body of the + /// request defines the query. + /// + /// See [RFC5323, Section 2][]. + /// + /// [RFC5323, Section 2]: https://tools.ietf.org/html/rfc5323#section-2 + Search, + + /// The TRACE method requests a remote, application-level loop-back of the request message. + /// + /// See [RFC7231, Section 4.3.8][]. + /// + /// [RFC7231, Section 4.3.8]: https://tools.ietf.org/html/rfc7231#section-4.3.8 + Trace, + + /// The UNBIND method modifies the collection identified by the Request- URI by removing the + /// binding identified by the segment specified in the UNBIND body. + /// + /// See [RFC5842, Section 5][]. + /// + /// [RFC5842, Section 5]: https://tools.ietf.org/html/rfc5842#section-5 + Unbind, + + /// An UNCHECKOUT request can be applied to a checked-out version-controlled resource to cancel + /// the CHECKOUT and restore the pre-CHECKOUT state of the version-controlled resource. + /// + /// See [RFC3253, Section 4.5][]. + /// + /// [RFC3253, Section 4.5]: https://tools.ietf.org/html/rfc3253#section-4.5 + Uncheckout, + + /// The UNLINK method removes one or more Link relationships from the existing resource + /// identified by the Request-URI. + /// + /// See [RFC2068, Section 19.6.1.3][]. + /// + /// [RFC2068, Section 19.6.1.3]: https://tools.ietf.org/html/rfc2068#section-19.6.1.3 + Unlink, + + /// The UNLOCK method removes the lock identified by the lock token in the Lock-Token request + /// header. + /// + /// See [RFC4918, Section 9.11][]. + /// + /// [RFC4918, Section 9.11]: https://tools.ietf.org/html/rfc4918#section-9.11 + Unlock, + + /// The UPDATE method modifies the content and dead properties of a checked-in + /// version-controlled resource (the "update target") to be those of a specified version (the + /// "update source") from the version history of that version-controlled resource. + /// + /// See [RFC3253, Section 7.1][]. + /// + /// [RFC3253, Section 7.1]: https://tools.ietf.org/html/rfc3253#section-7.1 + Update, + + /// The UPDATEREDIRECTREF method requests the update of a redirect reference resource. + /// + /// See [RFC4437, Section 7][]. + /// + /// [RFC4437, Section 7]: https://tools.ietf.org/html/rfc4437#section-7 + UpdateRedirectRef, + + /// A VERSION-CONTROL request can be used to create a version-controlled resource at the + /// request-URL. + /// + /// See [RFC3253, Section 3.5]. + /// + /// [RFC3253, Section 3.5]: https://tools.ietf.org/html/rfc3253#section-3.5 + VersionControl, +} + +impl Method { + /// Whether a method is considered "safe", meaning the request is essentially read-only. + /// + /// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.1) for more details. + pub fn is_safe(&self) -> bool { + matches!( + self, + Method::Get + | Method::Head + | Method::Options + | Method::Pri + | Method::PropFind + | Method::Report + | Method::Search + | Method::Trace + ) + } +} + +#[cfg(feature = "json")] +mod serde { + use super::Method; + use serde::de::{Error as DeError, Unexpected, Visitor}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use std::fmt; + use std::str::FromStr; + + struct MethodVisitor; + + impl<'de> Visitor<'de> for MethodVisitor { + type Value = Method; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a HTTP method &str") + } + + fn visit_str(self, v: &str) -> Result + where + E: DeError, + { + match Method::from_str(v) { + Ok(method) => Ok(method), + Err(_) => Err(DeError::invalid_value(Unexpected::Str(v), &self)), + } + } + } + + impl<'de> Deserialize<'de> for Method { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(MethodVisitor) + } + } + + impl Serialize for Method { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self.as_ref()) + } + } +} + +impl Display for Method { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(AsRef::::as_ref(self)) + } +} + +impl FromStr for Method { + type Err = InvalidMethod; + + fn from_str(s: &str) -> Result { + #[allow(clippy::match_str_case_mismatch)] + match &*s.to_ascii_uppercase() { + "ACL" => Ok(Self::Acl), + "BASELINE-CONTROL" => Ok(Self::BaselineControl), + "BIND" => Ok(Self::Bind), + "CHECKIN" => Ok(Self::Checkin), + "CHECKOUT" => Ok(Self::Checkout), + "CONNECT" => Ok(Self::Connect), + "COPY" => Ok(Self::Copy), + "DELETE" => Ok(Self::Delete), + "GET" => Ok(Self::Get), + "HEAD" => Ok(Self::Head), + "LABEL" => Ok(Self::Label), + "LINK" => Ok(Self::Link), + "LOCK" => Ok(Self::Lock), + "MERGE" => Ok(Self::Merge), + "MKACTIVITY" => Ok(Self::MkActivity), + "MKCALENDAR" => Ok(Self::MkCalendar), + "MKCOL" => Ok(Self::MkCol), + "MKREDIRECTREF" => Ok(Self::MkRedirectRef), + "MKWORKSPACE" => Ok(Self::MkWorkspace), + "MOVE" => Ok(Self::Move), + "OPTIONS" => Ok(Self::Options), + "ORDERPATCH" => Ok(Self::OrderPatch), + "PATCH" => Ok(Self::Patch), + "POST" => Ok(Self::Post), + "PRI" => Ok(Self::Pri), + "PROPFIND" => Ok(Self::PropFind), + "PROPPATCH" => Ok(Self::PropPatch), + "PUT" => Ok(Self::Put), + "REBIND" => Ok(Self::Rebind), + "REPORT" => Ok(Self::Report), + "SEARCH" => Ok(Self::Search), + "TRACE" => Ok(Self::Trace), + "UNBIND" => Ok(Self::Unbind), + "UNCHECKOUT" => Ok(Self::Uncheckout), + "UNLINK" => Ok(Self::Unlink), + "UNLOCK" => Ok(Self::Unlock), + "UPDATE" => Ok(Self::Update), + "UPDATEREDIRECTREF" => Ok(Self::UpdateRedirectRef), + "VERSION-CONTROL" => Ok(Self::VersionControl), + _ => Err(InvalidMethod::new()), + } + } +} + +impl<'a> std::convert::TryFrom<&'a str> for Method { + type Error = InvalidMethod; + + fn try_from(value: &'a str) -> Result { + Self::from_str(value) + } +} + +impl AsRef for Method { + fn as_ref(&self) -> &str { + match self { + Self::Acl => "ACL", + Self::BaselineControl => "BASELINE-CONTROL", + Self::Bind => "BIND", + Self::Checkin => "CHECKIN", + Self::Checkout => "CHECKOUT", + Self::Connect => "CONNECT", + Self::Copy => "COPY", + Self::Delete => "DELETE", + Self::Get => "GET", + Self::Head => "HEAD", + Self::Label => "LABEL", + Self::Link => "LINK", + Self::Lock => "LOCK", + Self::Merge => "MERGE", + Self::MkActivity => "MKACTIVITY", + Self::MkCalendar => "MKCALENDAR", + Self::MkCol => "MKCOL", + Self::MkRedirectRef => "MKREDIRECTREF", + Self::MkWorkspace => "MKWORKSPACE", + Self::Move => "MOVE", + Self::Options => "OPTIONS", + Self::OrderPatch => "ORDERPATCH", + Self::Patch => "PATCH", + Self::Post => "POST", + Self::Pri => "PRI", + Self::PropFind => "PROPFIND", + Self::PropPatch => "PROPPATCH", + Self::Put => "PUT", + Self::Rebind => "REBIND", + Self::Report => "REPORT", + Self::Search => "SEARCH", + Self::Trace => "TRACE", + Self::Unbind => "UNBIND", + Self::Uncheckout => "UNCHECKOUT", + Self::Unlink => "UNLINK", + Self::Unlock => "UNLOCK", + Self::Update => "UPDATE", + Self::UpdateRedirectRef => "UPDATEREDIRECTREF", + Self::VersionControl => "VERSION-CONTROL", + } + } +} + +/// A possible error value when converting `Method` from bytes. +pub struct InvalidMethod { + _priv: (), +} + +impl InvalidMethod { + fn new() -> InvalidMethod { + InvalidMethod { _priv: () } + } +} + +impl Debug for InvalidMethod { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("InvalidMethod") + // skip _priv noise + .finish() + } +} + +impl Display for InvalidMethod { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Invalid HTTP method") + } +} + +impl Error for InvalidMethod {} + +#[cfg(test)] +mod test { + use std::collections::HashSet; + + use super::{InvalidMethod, Method}; + + #[test] + fn serde() -> Result<(), serde_json::Error> { + assert_eq!(Method::Get, serde_json::from_str("\"GET\"")?); + assert_eq!(Some("PATCH"), serde_json::to_value(Method::Patch)?.as_str()); + Ok(()) + } + + #[test] + fn serde_fail() { + serde_json::from_str::("\"ABC\"").expect_err("Did deserialize from invalid string"); + } + + #[test] + fn names() -> Result<(), InvalidMethod> { + let method_names = [ + "ACL", + "BASELINE-CONTROL", + "BIND", + "CHECKIN", + "CHECKOUT", + "CONNECT", + "COPY", + "DELETE", + "GET", + "HEAD", + "LABEL", + "LINK", + "LOCK", + "MERGE", + "MKACTIVITY", + "MKCALENDAR", + "MKCOL", + "MKREDIRECTREF", + "MKWORKSPACE", + "MOVE", + "OPTIONS", + "ORDERPATCH", + "PATCH", + "POST", + "PRI", + "PROPFIND", + "PROPPATCH", + "PUT", + "REBIND", + "REPORT", + "SEARCH", + "TRACE", + "UNBIND", + "UNCHECKOUT", + "UNLINK", + "UNLOCK", + "UPDATE", + "UPDATEREDIRECTREF", + "VERSION-CONTROL", + ]; + + let methods = method_names + .iter() + .map(|s| s.parse::()) + .collect::, _>>()?; + + // check that we didn't accidentally map two methods to the same variant + assert_eq!(methods.len(), method_names.len()); + + // check that a method's name and the name it is parsed from match + for method in methods { + assert_eq!(method.as_ref().parse::()?, method); + } + + Ok(()) + } +} diff --git a/sdk/typespec/src/status_code.rs b/sdk/typespec/src/status_code.rs new file mode 100644 index 0000000000..ef941b7087 --- /dev/null +++ b/sdk/typespec/src/status_code.rs @@ -0,0 +1,758 @@ +// Source: https://github.com/http-rs/http-types/blob/v2.12.0/src/status_code.rs +// InvalidStatusCode source: https://github.com/hyperium/http/blob/v1.1.0/src/status.rs +use std::fmt::{self, Debug, Display}; + +/// HTTP response status codes. +/// +/// As defined by [rfc7231 section 6](https://tools.ietf.org/html/rfc7231#section-6). +/// [Read more](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) +#[repr(u16)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub enum StatusCode { + /// 100 Continue + /// + /// This interim response indicates that everything so far is OK and that + /// the client should continue the request, or ignore the response if + /// the request is already finished. + Continue = 100, + + /// 101 Switching Protocols + /// + /// This code is sent in response to an Upgrade request header from the + /// client, and indicates the protocol the server is switching to. + SwitchingProtocols = 101, + + /// 103 Early Hints + /// + /// This status code is primarily intended to be used with the Link header, + /// letting the user agent start preloading resources while the server + /// prepares a response. + EarlyHints = 103, + + /// 200 Ok + /// + /// The request has succeeded + Ok = 200, + + /// 201 Created + /// + /// The request has succeeded and a new resource has been created as a + /// result. This is typically the response sent after POST requests, or + /// some PUT requests. + Created = 201, + + /// 202 Accepted + /// + /// The request has been received but not yet acted upon. It is + /// noncommittal, since there is no way in HTTP to later send an + /// asynchronous response indicating the outcome of the request. It is + /// intended for cases where another process or server handles the request, + /// or for batch processing. + Accepted = 202, + + /// 203 Non Authoritative Information + /// + /// This response code means the returned meta-information is not exactly + /// the same as is available from the origin server, but is collected + /// from a local or a third-party copy. This is mostly used for mirrors + /// or backups of another resource. Except for that specific case, the + /// "200 OK" response is preferred to this status. + NonAuthoritativeInformation = 203, + + /// 204 No Content + /// + /// There is no content to send for this request, but the headers may be + /// useful. The user-agent may update its cached headers for this + /// resource with the new ones. + NoContent = 204, + + /// 205 Reset Content + /// + /// Tells the user-agent to reset the document which sent this request. + ResetContent = 205, + + /// 206 Partial Content + /// + /// This response code is used when the Range header is sent from the client + /// to request only part of a resource. + PartialContent = 206, + + /// 207 Multi-Status + /// + /// A Multi-Status response conveys information about + /// multiple resources in situations where multiple + /// status codes might be appropriate. + MultiStatus = 207, + + /// 226 Im Used + /// + /// The server has fulfilled a GET request for the resource, and the + /// response is a representation of the result of one or more + /// instance-manipulations applied to the current instance. + ImUsed = 226, + + /// 300 Multiple Choice + /// + /// The request has more than one possible response. The user-agent or user + /// should choose one of them. (There is no standardized way of choosing + /// one of the responses, but HTML links to the possibilities are + /// recommended so the user can pick.) + MultipleChoice = 300, + + /// 301 Moved Permanently + /// + /// The URL of the requested resource has been changed permanently. The new + /// URL is given in the response. + MovedPermanently = 301, + + /// 302 Found + /// + /// This response code means that the URI of requested resource has been + /// changed temporarily. Further changes in the URI might be made in the + /// future. Therefore, this same URI should be used by the client in + /// future requests. + Found = 302, + + /// 303 See Other + /// + /// The server sent this response to direct the client to get the requested + /// resource at another URI with a GET request. + SeeOther = 303, + + /// 304 Not Modified + /// + /// This is used for caching purposes. It tells the client that the response + /// has not been modified, so the client can continue to use the same + /// cached version of the response. + NotModified = 304, + + /// 307 Temporary Redirect + /// + /// The server sends this response to direct the client to get the requested + /// resource at another URI with same method that was used in the prior + /// request. This has the same semantics as the 302 Found HTTP response + /// code, with the exception that the user agent must not change the + /// HTTP method used: If a POST was used in the first request, a POST must + /// be used in the second request. + TemporaryRedirect = 307, + + /// 308 Permanent Redirect + /// + /// This means that the resource is now permanently located at another URI, + /// specified by the Location: HTTP Response header. This has the same + /// semantics as the 301 Moved Permanently HTTP response code, with the + /// exception that the user agent must not change the HTTP method + /// used: If a POST was used in the first request, a POST must be used in + /// the second request. + PermanentRedirect = 308, + + /// 400 Bad Request + /// + /// The server could not understand the request due to invalid syntax. + BadRequest = 400, + + /// 401 Unauthorized + /// + /// Although the HTTP standard specifies "unauthorized", semantically this + /// response means "unauthenticated". That is, the client must + /// authenticate itself to get the requested response. + Unauthorized = 401, + + /// 402 Payment Required + /// + /// This response code is reserved for future use. The initial aim for + /// creating this code was using it for digital payment systems, however + /// this status code is used very rarely and no standard convention + /// exists. + PaymentRequired = 402, + + /// 403 Forbidden + /// + /// The client does not have access rights to the content; that is, it is + /// unauthorized, so the server is refusing to give the requested + /// resource. Unlike 401, the client's identity is known to the server. + Forbidden = 403, + + /// 404 Not Found + /// + /// The server can not find requested resource. In the browser, this means + /// the URL is not recognized. In an API, this can also mean that the + /// endpoint is valid but the resource itself does not exist. Servers + /// may also send this response instead of 403 to hide the existence of + /// a resource from an unauthorized client. This response code is probably + /// the most famous one due to its frequent occurrence on the web. + NotFound = 404, + + /// 405 Method Not Allowed + /// + /// The request method is known by the server but has been disabled and + /// cannot be used. For example, an API may forbid DELETE-ing a + /// resource. The two mandatory methods, GET and HEAD, must never be + /// disabled and should not return this error code. + MethodNotAllowed = 405, + + /// 406 Not Acceptable + /// + /// This response is sent when the web server, after performing + /// server-driven content negotiation, doesn't find any content that + /// conforms to the criteria given by the user agent. + NotAcceptable = 406, + + /// 407 Proxy Authentication Required + /// + /// This is similar to 401 but authentication is needed to be done by a + /// proxy. + ProxyAuthenticationRequired = 407, + + /// 408 Request Timeout + /// + /// This response is sent on an idle connection by some servers, even + /// without any previous request by the client. It means that the server + /// would like to shut down this unused connection. This response is + /// used much more since some browsers, like Chrome, Firefox 27+, + /// or IE9, use HTTP pre-connection mechanisms to speed up surfing. Also + /// note that some servers merely shut down the connection without + /// sending this message. + RequestTimeout = 408, + + /// 409 Conflict + /// + /// This response is sent when a request conflicts with the current state of + /// the server. + Conflict = 409, + + /// 410 Gone + /// + /// This response is sent when the requested content has been permanently + /// deleted from server, with no forwarding address. Clients are + /// expected to remove their caches and links to the resource. The HTTP + /// specification intends this status code to be used for "limited-time, + /// promotional services". APIs should not feel compelled to indicate + /// resources that have been deleted with this status code. + Gone = 410, + + /// 411 Length Required + /// + /// Server rejected the request because the Content-Length header field is + /// not defined and the server requires it. + LengthRequired = 411, + + /// 412 Precondition Failed + /// + /// The client has indicated preconditions in its headers which the server + /// does not meet. + PreconditionFailed = 412, + + /// 413 Payload Too Large + /// + /// Request entity is larger than limits defined by server; the server might + /// close the connection or return an Retry-After header field. + PayloadTooLarge = 413, + + /// 414 URI Too Long + /// + /// The URI requested by the client is longer than the server is willing to + /// interpret. + UriTooLong = 414, + + /// 415 Unsupported Media Type + /// + /// The media format of the requested data is not supported by the server, + /// so the server is rejecting the request. + UnsupportedMediaType = 415, + + /// 416 Requested Range Not Satisfiable + /// + /// The range specified by the Range header field in the request can't be + /// fulfilled; it's possible that the range is outside the size of the + /// target URI's data. + RequestedRangeNotSatisfiable = 416, + + /// 417 Expectation Failed + /// + /// This response code means the expectation indicated by the Expect request + /// header field can't be met by the server. + ExpectationFailed = 417, + /// + /// 418 I'm a teapot + /// + /// The server refuses the attempt to brew coffee with a teapot. + ImATeapot = 418, + + /// 421 Misdirected Request + /// + /// The request was directed at a server that is not able to produce a + /// response. This can be sent by a server that is not configured to + /// produce responses for the combination of scheme and authority that + /// are included in the request URI. + MisdirectedRequest = 421, + + /// 422 Unprocessable Entity + /// + /// The request was well-formed but was unable to be followed due to + /// semantic errors. + UnprocessableEntity = 422, + + /// 423 Locked + /// + /// The resource that is being accessed is locked. + Locked = 423, + + /// 424 Failed Dependency + /// + /// The request failed because it depended on another request and that + /// request failed (e.g., a PROPPATCH). + FailedDependency = 424, + + /// 425 Too Early + /// + /// Indicates that the server is unwilling to risk processing a request that + /// might be replayed. + TooEarly = 425, + + /// 426 Upgrade Required + /// + /// The server refuses to perform the request using the current protocol but + /// might be willing to do so after the client upgrades to a different + /// protocol. The server sends an Upgrade header in a 426 response to + /// indicate the required protocol(s). + UpgradeRequired = 426, + + /// 428 Precondition Required + /// + /// The origin server requires the request to be conditional. This response + /// is intended to prevent the 'lost update' problem, where a client + /// GETs a resource's state, modifies it, and PUTs it back to the + /// server, when meanwhile a third party has modified the state on the + /// server, leading to a conflict. + PreconditionRequired = 428, + + /// 429 Too Many Requests + /// + /// The user has sent too many requests in a given amount of time ("rate + /// limiting"). + TooManyRequests = 429, + + /// 431 Request Header Fields Too Large + /// + /// The server is unwilling to process the request because its header fields + /// are too large. The request may be resubmitted after reducing the + /// size of the request header fields. + RequestHeaderFieldsTooLarge = 431, + + /// 451 Unavailable For Legal Reasons + /// + /// The user-agent requested a resource that cannot legally be provided, + /// such as a web page censored by a government. + UnavailableForLegalReasons = 451, + + /// 500 Internal Server Error + /// + /// The server has encountered a situation it doesn't know how to handle. + InternalServerError = 500, + + /// 501 Not Implemented + /// + /// The request method is not supported by the server and cannot be handled. + /// The only methods that servers are required to support (and therefore + /// that must not return this code) are GET and HEAD. + NotImplemented = 501, + + /// 502 Bad Gateway + /// + /// This error response means that the server, while working as a gateway to + /// get a response needed to handle the request, got an invalid + /// response. + BadGateway = 502, + + /// 503 Service Unavailable + /// + /// The server is not ready to handle the request. Common causes are a + /// server that is down for maintenance or that is overloaded. Note that + /// together with this response, a user-friendly page explaining the + /// problem should be sent. This responses should be used for temporary + /// conditions and the Retry-After: HTTP header should, if possible, contain + /// the estimated time before the recovery of the service. The webmaster + /// must also take care about the caching-related headers that are sent + /// along with this response, as these temporary condition responses + /// should usually not be cached. + ServiceUnavailable = 503, + + /// 504 Gateway Timeout + /// + /// This error response is given when the server is acting as a gateway and + /// cannot get a response in time. + GatewayTimeout = 504, + + /// 505 HTTP Version Not Supported + /// + /// The HTTP version used in the request is not supported by the server. + HttpVersionNotSupported = 505, + + /// 506 Variant Also Negotiates + /// + /// The server has an internal configuration error: the chosen variant + /// resource is configured to engage in transparent content negotiation + /// itself, and is therefore not a proper end point in the negotiation + /// process. + VariantAlsoNegotiates = 506, + + /// 507 Insufficient Storage + /// + /// The server is unable to store the representation needed to complete the + /// request. + InsufficientStorage = 507, + + /// 508 Loop Detected + /// + /// The server detected an infinite loop while processing the request. + LoopDetected = 508, + + /// 510 Not Extended + /// + /// Further extensions to the request are required for the server to fulfil + /// it. + NotExtended = 510, + + /// 511 Network Authentication Required + /// + /// The 511 status code indicates that the client needs to authenticate to + /// gain network access. + NetworkAuthenticationRequired = 511, +} + +impl StatusCode { + /// Returns `true` if the status code is `1xx` range. + /// + /// If this returns `true` it indicates that the request was received, + /// continuing process. + pub fn is_informational(&self) -> bool { + let num: u16 = (*self).into(); + (100..200).contains(&num) + } + + /// Returns `true` if the status code is the `2xx` range. + /// + /// If this returns `true` it indicates that the request was successfully + /// received, understood, and accepted. + pub fn is_success(&self) -> bool { + let num: u16 = (*self).into(); + (200..300).contains(&num) + } + + /// Returns `true` if the status code is the `3xx` range. + /// + /// If this returns `true` it indicates that further action needs to be + /// taken in order to complete the request. + pub fn is_redirection(&self) -> bool { + let num: u16 = (*self).into(); + (300..400).contains(&num) + } + + /// Returns `true` if the status code is the `4xx` range. + /// + /// If this returns `true` it indicates that the request contains bad syntax + /// or cannot be fulfilled. + pub fn is_client_error(&self) -> bool { + let num: u16 = (*self).into(); + (400..500).contains(&num) + } + + /// Returns `true` if the status code is the `5xx` range. + /// + /// If this returns `true` it indicates that the server failed to fulfill an + /// apparently valid request. + pub fn is_server_error(&self) -> bool { + let num: u16 = (*self).into(); + (500..600).contains(&num) + } + + /// The canonical reason for a given status code + pub fn canonical_reason(&self) -> &'static str { + match self { + StatusCode::Continue => "Continue", + StatusCode::SwitchingProtocols => "Switching Protocols", + StatusCode::EarlyHints => "Early Hints", + StatusCode::Ok => "OK", + StatusCode::Created => "Created", + StatusCode::Accepted => "Accepted", + StatusCode::NonAuthoritativeInformation => "Non Authoritative Information", + StatusCode::NoContent => "No Content", + StatusCode::ResetContent => "Reset Content", + StatusCode::PartialContent => "Partial Content", + StatusCode::MultiStatus => "Multi-Status", + StatusCode::ImUsed => "Im Used", + StatusCode::MultipleChoice => "Multiple Choice", + StatusCode::MovedPermanently => "Moved Permanently", + StatusCode::Found => "Found", + StatusCode::SeeOther => "See Other", + StatusCode::NotModified => "Not Modified", + StatusCode::TemporaryRedirect => "Temporary Redirect", + StatusCode::PermanentRedirect => "Permanent Redirect", + StatusCode::BadRequest => "Bad Request", + StatusCode::Unauthorized => "Unauthorized", + StatusCode::PaymentRequired => "Payment Required", + StatusCode::Forbidden => "Forbidden", + StatusCode::NotFound => "Not Found", + StatusCode::MethodNotAllowed => "Method Not Allowed", + StatusCode::NotAcceptable => "Not Acceptable", + StatusCode::ProxyAuthenticationRequired => "Proxy Authentication Required", + StatusCode::RequestTimeout => "Request Timeout", + StatusCode::Conflict => "Conflict", + StatusCode::Gone => "Gone", + StatusCode::LengthRequired => "Length Required", + StatusCode::PreconditionFailed => "Precondition Failed", + StatusCode::PayloadTooLarge => "Payload Too Large", + StatusCode::UriTooLong => "URI Too Long", + StatusCode::UnsupportedMediaType => "Unsupported Media Type", + StatusCode::RequestedRangeNotSatisfiable => "Requested Range Not Satisfiable", + StatusCode::ExpectationFailed => "Expectation Failed", + StatusCode::ImATeapot => "I'm a teapot", + StatusCode::MisdirectedRequest => "Misdirected Request", + StatusCode::UnprocessableEntity => "Unprocessable Entity", + StatusCode::Locked => "Locked", + StatusCode::FailedDependency => "Failed Dependency", + StatusCode::TooEarly => "Too Early", + StatusCode::UpgradeRequired => "Upgrade Required", + StatusCode::PreconditionRequired => "Precondition Required", + StatusCode::TooManyRequests => "Too Many Requests", + StatusCode::RequestHeaderFieldsTooLarge => "Request Header Fields Too Large", + StatusCode::UnavailableForLegalReasons => "Unavailable For Legal Reasons", + StatusCode::InternalServerError => "Internal Server Error", + StatusCode::NotImplemented => "Not Implemented", + StatusCode::BadGateway => "Bad Gateway", + StatusCode::ServiceUnavailable => "Service Unavailable", + StatusCode::GatewayTimeout => "Gateway Timeout", + StatusCode::HttpVersionNotSupported => "HTTP Version Not Supported", + StatusCode::VariantAlsoNegotiates => "Variant Also Negotiates", + StatusCode::InsufficientStorage => "Insufficient Storage", + StatusCode::LoopDetected => "Loop Detected", + StatusCode::NotExtended => "Not Extended", + StatusCode::NetworkAuthenticationRequired => "Network Authentication Required", + } + } +} + +/// A possible error value when converting a `StatusCode` from a `u16` or `&str` +/// +/// This error indicates that the supplied input was not a valid number, was less +/// than 100, or was greater than 999. +pub struct InvalidStatusCode { + _priv: (), +} + +impl InvalidStatusCode { + fn new() -> InvalidStatusCode { + InvalidStatusCode { _priv: () } + } +} + +impl Debug for InvalidStatusCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("InvalidStatusCode") + // skip _priv noise + .finish() + } +} + +impl Display for InvalidStatusCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Invalid status code") + } +} + +impl std::error::Error for InvalidStatusCode {} + +#[cfg(feature = "json")] +mod serde { + use super::StatusCode; + use serde::de::{Error as DeError, Unexpected, Visitor}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use std::fmt; + + impl Serialize for StatusCode { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let value: u16 = *self as u16; + serializer.serialize_u16(value) + } + } + + struct StatusCodeU16Visitor; + + impl<'de> Visitor<'de> for StatusCodeU16Visitor { + type Value = StatusCode; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a u16 representing the status code") + } + + fn visit_i16(self, v: i16) -> Result + where + E: DeError, + { + self.visit_u16(v as u16) + } + + fn visit_i32(self, v: i32) -> Result + where + E: DeError, + { + self.visit_u16(v as u16) + } + + fn visit_i64(self, v: i64) -> Result + where + E: DeError, + { + self.visit_u16(v as u16) + } + + fn visit_u16(self, v: u16) -> Result + where + E: DeError, + { + use std::convert::TryFrom; + match StatusCode::try_from(v) { + Ok(status_code) => Ok(status_code), + Err(_) => Err(DeError::invalid_value( + Unexpected::Unsigned(v as u64), + &self, + )), + } + } + + fn visit_u32(self, v: u32) -> Result + where + E: DeError, + { + self.visit_u16(v as u16) + } + + fn visit_u64(self, v: u64) -> Result + where + E: DeError, + { + self.visit_u16(v as u16) + } + } + + impl<'de> Deserialize<'de> for StatusCode { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(StatusCodeU16Visitor) + } + } +} + +impl From for u16 { + fn from(code: StatusCode) -> u16 { + code as u16 + } +} + +impl std::convert::TryFrom for StatusCode { + type Error = InvalidStatusCode; + + fn try_from(num: u16) -> Result { + match num { + 100 => Ok(StatusCode::Continue), + 101 => Ok(StatusCode::SwitchingProtocols), + 103 => Ok(StatusCode::EarlyHints), + 200 => Ok(StatusCode::Ok), + 201 => Ok(StatusCode::Created), + 202 => Ok(StatusCode::Accepted), + 203 => Ok(StatusCode::NonAuthoritativeInformation), + 204 => Ok(StatusCode::NoContent), + 205 => Ok(StatusCode::ResetContent), + 206 => Ok(StatusCode::PartialContent), + 207 => Ok(StatusCode::MultiStatus), + 226 => Ok(StatusCode::ImUsed), + 300 => Ok(StatusCode::MultipleChoice), + 301 => Ok(StatusCode::MovedPermanently), + 302 => Ok(StatusCode::Found), + 303 => Ok(StatusCode::SeeOther), + 304 => Ok(StatusCode::NotModified), + 307 => Ok(StatusCode::TemporaryRedirect), + 308 => Ok(StatusCode::PermanentRedirect), + 400 => Ok(StatusCode::BadRequest), + 401 => Ok(StatusCode::Unauthorized), + 402 => Ok(StatusCode::PaymentRequired), + 403 => Ok(StatusCode::Forbidden), + 404 => Ok(StatusCode::NotFound), + 405 => Ok(StatusCode::MethodNotAllowed), + 406 => Ok(StatusCode::NotAcceptable), + 407 => Ok(StatusCode::ProxyAuthenticationRequired), + 408 => Ok(StatusCode::RequestTimeout), + 409 => Ok(StatusCode::Conflict), + 410 => Ok(StatusCode::Gone), + 411 => Ok(StatusCode::LengthRequired), + 412 => Ok(StatusCode::PreconditionFailed), + 413 => Ok(StatusCode::PayloadTooLarge), + 414 => Ok(StatusCode::UriTooLong), + 415 => Ok(StatusCode::UnsupportedMediaType), + 416 => Ok(StatusCode::RequestedRangeNotSatisfiable), + 417 => Ok(StatusCode::ExpectationFailed), + 418 => Ok(StatusCode::ImATeapot), + 421 => Ok(StatusCode::MisdirectedRequest), + 422 => Ok(StatusCode::UnprocessableEntity), + 423 => Ok(StatusCode::Locked), + 424 => Ok(StatusCode::FailedDependency), + 425 => Ok(StatusCode::TooEarly), + 426 => Ok(StatusCode::UpgradeRequired), + 428 => Ok(StatusCode::PreconditionRequired), + 429 => Ok(StatusCode::TooManyRequests), + 431 => Ok(StatusCode::RequestHeaderFieldsTooLarge), + 451 => Ok(StatusCode::UnavailableForLegalReasons), + 500 => Ok(StatusCode::InternalServerError), + 501 => Ok(StatusCode::NotImplemented), + 502 => Ok(StatusCode::BadGateway), + 503 => Ok(StatusCode::ServiceUnavailable), + 504 => Ok(StatusCode::GatewayTimeout), + 505 => Ok(StatusCode::HttpVersionNotSupported), + 506 => Ok(StatusCode::VariantAlsoNegotiates), + 507 => Ok(StatusCode::InsufficientStorage), + 508 => Ok(StatusCode::LoopDetected), + 510 => Ok(StatusCode::NotExtended), + 511 => Ok(StatusCode::NetworkAuthenticationRequired), + _ => Err(InvalidStatusCode::new()), + } + } +} + +impl PartialEq for u16 { + fn eq(&self, other: &StatusCode) -> bool { + *self == *other as u16 + } +} + +impl PartialEq for StatusCode { + fn eq(&self, other: &u16) -> bool { + *self as u16 == *other + } +} + +impl Display for StatusCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", *self as u16) + } +} + +#[cfg(test)] +mod test { + use super::StatusCode; + #[test] + fn serde_as_u16() -> Result<(), serde_json::Error> { + let status_code: StatusCode = serde_json::from_str("202")?; + assert_eq!(StatusCode::Accepted, status_code); + assert_eq!( + Some(202), + serde_json::to_value(StatusCode::Accepted)?.as_u64() + ); + Ok(()) + } +} diff --git a/sdk/typespec/typespec_client_core/Cargo.toml b/sdk/typespec/typespec_client_core/Cargo.toml index 4efabf2756..08e8a7a859 100644 --- a/sdk/typespec/typespec_client_core/Cargo.toml +++ b/sdk/typespec/typespec_client_core/Cargo.toml @@ -16,7 +16,6 @@ base64.workspace = true bytes.workspace = true dyn-clone.workspace = true futures.workspace = true -http-types = { workspace = true, optional = true } pin-project.workspace = true quick-xml = { workspace = true, optional = true } rand.workspace = true @@ -48,7 +47,7 @@ typespec_macros.workspace = true [features] default = ["http", "json", "reqwest", "reqwest_gzip", "reqwest_rustls"] derive = ["dep:typespec_macros"] -http = ["dep:http-types", "typespec/http"] +http = ["typespec/http"] json = ["typespec/json"] reqwest = ["dep:reqwest", "reqwest/default-tls"] reqwest_gzip = ["reqwest/gzip"] diff --git a/sdk/typespec/typespec_client_core/src/http/mod.rs b/sdk/typespec/typespec_client_core/src/http/mod.rs index cf8ea37c94..00336a8873 100644 --- a/sdk/typespec/typespec_client_core/src/http/mod.rs +++ b/sdk/typespec/typespec_client_core/src/http/mod.rs @@ -25,7 +25,7 @@ pub use request::{Body, Request, RequestContent}; pub use response::{Model, Response}; // Re-export important types. -pub use http_types::{Method, StatusCode}; +pub use typespec::{Method, StatusCode}; pub use url::Url; /// Add a new query pair into the target [`Url`]'s query string. diff --git a/sdk/typespec/typespec_client_core/src/http/response.rs b/sdk/typespec/typespec_client_core/src/http/response.rs index 58c55ee4cf..23892e8c06 100644 --- a/sdk/typespec/typespec_client_core/src/http/response.rs +++ b/sdk/typespec/typespec_client_core/src/http/response.rs @@ -139,7 +139,7 @@ impl Response { /// # #[tokio::main] /// # async fn main() { /// # let r: Response = typespec_client_core::http::Response::from_bytes( - /// # http_types::StatusCode::Ok, + /// # typespec::StatusCode::Ok, /// # typespec_client_core::http::headers::Headers::new(), /// # "{\"name\":\"database_password\",\"value\":\"hunter2\"}", /// # ); @@ -185,7 +185,7 @@ impl Response { /// # impl SecretClient { /// # pub async fn get_secret(&self) -> typespec_client_core::http::Response { /// # typespec_client_core::http::Response::from_bytes( - /// # http_types::StatusCode::Ok, + /// # typespec::StatusCode::Ok, /// # typespec_client_core::http::headers::Headers::new(), /// # "{\"name\":\"database_password\",\"value\":\"hunter2\"}", /// # ) @@ -199,7 +199,7 @@ impl Response { /// # async fn main() { /// let secret_client = create_secret_client(); /// let response = secret_client.get_secret().await; - /// assert_eq!(response.status(), http_types::StatusCode::Ok); + /// assert_eq!(response.status(), typespec::StatusCode::Ok); /// let model = response.deserialize_body().await.unwrap(); /// assert_eq!(model.name, "database_password"); /// assert_eq!(model.value, "hunter2"); @@ -314,7 +314,7 @@ mod tests { // Create a response that fails as you read the body. let response = Response::<()>::new( - http_types::StatusCode::Ok, + typespec::StatusCode::Ok, Headers::new(), Box::pin(futures::stream::once(async { Err(ErrorKind::Other.into_error()) @@ -329,8 +329,8 @@ mod tests { mod json { use crate::http::headers::Headers; use crate::http::Response; - use http_types::StatusCode; use serde::Deserialize; + use typespec::StatusCode; use typespec_macros::Model; /// An example JSON-serialized response type. @@ -420,8 +420,8 @@ mod tests { mod xml { use crate::http::headers::Headers; use crate::http::Response; - use http_types::StatusCode; use serde::Deserialize; + use typespec::StatusCode; use typespec_macros::Model; /// An example XML-serialized response type.