From 30d64120afecbe076b49eef6985e2de8cfa8d0b1 Mon Sep 17 00:00:00 2001 From: Adam Leventhal Date: Fri, 13 May 2022 10:26:22 -0700 Subject: [PATCH] remove cross-package file dependency by adding progenitor_client::code() (#52) --- progenitor-client/src/lib.rs | 238 +------------------- progenitor-client/src/progenitor_client.rs | 240 +++++++++++++++++++++ progenitor/src/main.rs | 3 +- 3 files changed, 245 insertions(+), 236 deletions(-) create mode 100644 progenitor-client/src/progenitor_client.rs diff --git a/progenitor-client/src/lib.rs b/progenitor-client/src/lib.rs index f5e9e9d..6590ecd 100644 --- a/progenitor-client/src/lib.rs +++ b/progenitor-client/src/lib.rs @@ -1,240 +1,10 @@ // Copyright 2022 Oxide Computer Company -//! Support code for generated clients. +mod progenitor_client; -use std::{ - ops::{Deref, DerefMut}, - pin::Pin, -}; - -use bytes::Bytes; -use futures_core::Stream; -use serde::de::DeserializeOwned; - -/// Represents a streaming, untyped byte stream for both success and error -/// responses. -pub type ByteStream = - Pin> + Send>>; - -/// Success value returned by generated client methods. -pub struct ResponseValue { - inner: T, - status: reqwest::StatusCode, - headers: reqwest::header::HeaderMap, - // TODO cookies? -} - -impl ResponseValue { - #[doc(hidden)] - pub async fn from_response( - response: reqwest::Response, - ) -> Result> { - let status = response.status(); - let headers = response.headers().clone(); - let inner = response - .json() - .await - .map_err(Error::InvalidResponsePayload)?; - - Ok(Self { - inner, - status, - headers, - }) - } -} - -impl ResponseValue { - #[doc(hidden)] - pub fn stream(response: reqwest::Response) -> Self { - let status = response.status(); - let headers = response.headers().clone(); - Self { - inner: Box::pin(response.bytes_stream()), - status, - headers, - } - } -} - -impl ResponseValue<()> { - #[doc(hidden)] - pub fn empty(response: reqwest::Response) -> Self { - let status = response.status(); - let headers = response.headers().clone(); - // TODO is there anything we want to do to confirm that there is no - // content? - Self { - inner: (), - status, - headers, - } - } -} - -impl ResponseValue { - /// Consumes the ResponseValue, returning the wrapped value. - pub fn into_inner(self) -> T { - self.inner - } - - /// Get the status from this response. - pub fn status(&self) -> reqwest::StatusCode { - self.status - } - - /// Get the headers from this response. - pub fn headers(&self) -> &reqwest::header::HeaderMap { - &self.headers - } - - #[doc(hidden)] - pub fn map( - self, - f: F, - ) -> Result, E> - where - F: FnOnce(T) -> U, - { - let Self { - inner, - status, - headers, - } = self; - - Ok(ResponseValue { - inner: f(inner), - status, - headers, - }) - } -} - -impl Deref for ResponseValue { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for ResponseValue { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl std::fmt::Debug for ResponseValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner.fmt(f) - } -} - -/// Error produced by generated client methods. -/// -/// The type parameter may be a struct if there's a single expected error type -/// or an enum if there are multiple valid error types. It can be the unit type -/// if there are no structured returns expected. -pub enum Error { - /// A server error either with the data, or with the connection. - CommunicationError(reqwest::Error), - - /// A documented, expected error response. - ErrorResponse(ResponseValue), - - /// An expected response code whose deserialization failed. - // TODO we have stuff from the response; should we include it? - InvalidResponsePayload(reqwest::Error), - - /// A response not listed in the API description. This may represent a - /// success or failure response; check `status().is_success()`. - UnexpectedResponse(reqwest::Response), -} - -impl Error { - /// Returns the status code, if the error was generated from a response. - pub fn status(&self) -> Option { - match self { - Error::CommunicationError(e) => e.status(), - Error::ErrorResponse(rv) => Some(rv.status()), - Error::InvalidResponsePayload(e) => e.status(), - Error::UnexpectedResponse(r) => Some(r.status()), - } - } - - /// Convert this error into one without a typed body for unified error - /// handling with APIs that distinguish various error response bodies. - pub fn into_untyped(self) -> Error { - match self { - Error::CommunicationError(e) => Error::CommunicationError(e), - Error::ErrorResponse(ResponseValue { - inner: _, - status, - headers, - }) => Error::ErrorResponse(ResponseValue { - inner: (), - status, - headers, - }), - Error::InvalidResponsePayload(e) => { - Error::InvalidResponsePayload(e) - } - Error::UnexpectedResponse(r) => Error::UnexpectedResponse(r), - } - } -} - -impl From for Error { - fn from(e: reqwest::Error) -> Self { - Self::CommunicationError(e) - } -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Error::CommunicationError(e) => { - write!(f, "Communication Error {}", e) - } - Error::ErrorResponse(_) => { - write!(f, "Error Response") - } - Error::InvalidResponsePayload(e) => { - write!(f, "Invalid Response Payload {}", e) - } - Error::UnexpectedResponse(r) => { - write!(f, "Unexpected Response {:?}", r) - } - } - } -} -impl std::fmt::Debug for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self, f) - } -} -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Error::CommunicationError(e) => Some(e), - Error::InvalidResponsePayload(e) => Some(e), - _ => None, - } - } -} - -const PATH_SET: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS - .add(b' ') - .add(b'"') - .add(b'#') - .add(b'<') - .add(b'>') - .add(b'?') - .add(b'`') - .add(b'{') - .add(b'}'); +pub use crate::progenitor_client::*; #[doc(hidden)] -pub fn encode_path(pc: &str) -> String { - percent_encoding::utf8_percent_encode(pc, PATH_SET).to_string() +pub fn code() -> &'static str { + include_str!("progenitor_client.rs") } diff --git a/progenitor-client/src/progenitor_client.rs b/progenitor-client/src/progenitor_client.rs new file mode 100644 index 0000000..f5e9e9d --- /dev/null +++ b/progenitor-client/src/progenitor_client.rs @@ -0,0 +1,240 @@ +// Copyright 2022 Oxide Computer Company + +//! Support code for generated clients. + +use std::{ + ops::{Deref, DerefMut}, + pin::Pin, +}; + +use bytes::Bytes; +use futures_core::Stream; +use serde::de::DeserializeOwned; + +/// Represents a streaming, untyped byte stream for both success and error +/// responses. +pub type ByteStream = + Pin> + Send>>; + +/// Success value returned by generated client methods. +pub struct ResponseValue { + inner: T, + status: reqwest::StatusCode, + headers: reqwest::header::HeaderMap, + // TODO cookies? +} + +impl ResponseValue { + #[doc(hidden)] + pub async fn from_response( + response: reqwest::Response, + ) -> Result> { + let status = response.status(); + let headers = response.headers().clone(); + let inner = response + .json() + .await + .map_err(Error::InvalidResponsePayload)?; + + Ok(Self { + inner, + status, + headers, + }) + } +} + +impl ResponseValue { + #[doc(hidden)] + pub fn stream(response: reqwest::Response) -> Self { + let status = response.status(); + let headers = response.headers().clone(); + Self { + inner: Box::pin(response.bytes_stream()), + status, + headers, + } + } +} + +impl ResponseValue<()> { + #[doc(hidden)] + pub fn empty(response: reqwest::Response) -> Self { + let status = response.status(); + let headers = response.headers().clone(); + // TODO is there anything we want to do to confirm that there is no + // content? + Self { + inner: (), + status, + headers, + } + } +} + +impl ResponseValue { + /// Consumes the ResponseValue, returning the wrapped value. + pub fn into_inner(self) -> T { + self.inner + } + + /// Get the status from this response. + pub fn status(&self) -> reqwest::StatusCode { + self.status + } + + /// Get the headers from this response. + pub fn headers(&self) -> &reqwest::header::HeaderMap { + &self.headers + } + + #[doc(hidden)] + pub fn map( + self, + f: F, + ) -> Result, E> + where + F: FnOnce(T) -> U, + { + let Self { + inner, + status, + headers, + } = self; + + Ok(ResponseValue { + inner: f(inner), + status, + headers, + }) + } +} + +impl Deref for ResponseValue { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for ResponseValue { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl std::fmt::Debug for ResponseValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.inner.fmt(f) + } +} + +/// Error produced by generated client methods. +/// +/// The type parameter may be a struct if there's a single expected error type +/// or an enum if there are multiple valid error types. It can be the unit type +/// if there are no structured returns expected. +pub enum Error { + /// A server error either with the data, or with the connection. + CommunicationError(reqwest::Error), + + /// A documented, expected error response. + ErrorResponse(ResponseValue), + + /// An expected response code whose deserialization failed. + // TODO we have stuff from the response; should we include it? + InvalidResponsePayload(reqwest::Error), + + /// A response not listed in the API description. This may represent a + /// success or failure response; check `status().is_success()`. + UnexpectedResponse(reqwest::Response), +} + +impl Error { + /// Returns the status code, if the error was generated from a response. + pub fn status(&self) -> Option { + match self { + Error::CommunicationError(e) => e.status(), + Error::ErrorResponse(rv) => Some(rv.status()), + Error::InvalidResponsePayload(e) => e.status(), + Error::UnexpectedResponse(r) => Some(r.status()), + } + } + + /// Convert this error into one without a typed body for unified error + /// handling with APIs that distinguish various error response bodies. + pub fn into_untyped(self) -> Error { + match self { + Error::CommunicationError(e) => Error::CommunicationError(e), + Error::ErrorResponse(ResponseValue { + inner: _, + status, + headers, + }) => Error::ErrorResponse(ResponseValue { + inner: (), + status, + headers, + }), + Error::InvalidResponsePayload(e) => { + Error::InvalidResponsePayload(e) + } + Error::UnexpectedResponse(r) => Error::UnexpectedResponse(r), + } + } +} + +impl From for Error { + fn from(e: reqwest::Error) -> Self { + Self::CommunicationError(e) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Error::CommunicationError(e) => { + write!(f, "Communication Error {}", e) + } + Error::ErrorResponse(_) => { + write!(f, "Error Response") + } + Error::InvalidResponsePayload(e) => { + write!(f, "Invalid Response Payload {}", e) + } + Error::UnexpectedResponse(r) => { + write!(f, "Unexpected Response {:?}", r) + } + } + } +} +impl std::fmt::Debug for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Error::CommunicationError(e) => Some(e), + Error::InvalidResponsePayload(e) => Some(e), + _ => None, + } + } +} + +const PATH_SET: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS + .add(b' ') + .add(b'"') + .add(b'#') + .add(b'<') + .add(b'>') + .add(b'?') + .add(b'`') + .add(b'{') + .add(b'}'); + +#[doc(hidden)] +pub fn encode_path(pc: &str) -> String { + percent_encoding::utf8_percent_encode(pc, PATH_SET).to_string() +} diff --git a/progenitor/src/main.rs b/progenitor/src/main.rs index de84a01..10bdbbe 100644 --- a/progenitor/src/main.rs +++ b/progenitor/src/main.rs @@ -117,8 +117,7 @@ fn main() -> Result<()> { /* * Create the Rust source file containing the support code: */ - let progenitor_client_code = - include_str!("../../progenitor-client/src/lib.rs"); + let progenitor_client_code = progenitor_client::code(); let mut clientrs = src; clientrs.push("progenitor_client.rs"); save(clientrs, progenitor_client_code)?;