From a91a9cef65485bd85c24b1db1813211e9bcaf0f7 Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Fri, 2 May 2025 23:11:29 +0000 Subject: [PATCH 01/11] start building Format/DeserializeWith trait --- .../typespec_client_core/src/http/format.rs | 65 ++++++++ .../typespec_client_core/src/http/mod.rs | 2 + .../typespec_client_core/src/http/response.rs | 150 +----------------- 3 files changed, 73 insertions(+), 144 deletions(-) create mode 100644 sdk/typespec/typespec_client_core/src/http/format.rs diff --git a/sdk/typespec/typespec_client_core/src/http/format.rs b/sdk/typespec/typespec_client_core/src/http/format.rs new file mode 100644 index 0000000000..5dc8279e98 --- /dev/null +++ b/sdk/typespec/typespec_client_core/src/http/format.rs @@ -0,0 +1,65 @@ +use serde::de::DeserializeOwned; + +use crate::http::response::ResponseBody; + +/// A marker trait used to indicate the serialization format used for a response body. +/// +/// The [`Response`] type uses this trait, in the `F` parameter, to determine how to deserialize the body in to the `T` model when using [`Response::into_body`]. +/// +/// ## How this trait works +/// +/// This trait is a little funky, in order to allow the deserialization behavior of the format to be adjusted based on the type of the response body. +/// This is just a marker trait, it has no methods. +/// Instead, the method to actually perform the deserialization is defined in the [`DeserializeWith`] trait. +/// This trait is parameterized by a type that implements the [`Format`] trait. +pub trait Format {} + +/// A trait used to describe a type that can be deserialized using the specified [`Format`]. +/// +/// This trait defines the `deserialize_with` method, which takes a [`ResponseBody`] and returns the deserialized value. +/// The `F` type parameter allows for different implementations of the `deserialize_with` method based on the specific [`Format`] marker type used. +#[async_trait::async_trait] +pub trait DeserializeWith: Sized { + async fn deserialize_with(body: ResponseBody) -> typespec::Result; +} + +/// Implements [`DeserializeWith`] for [`ResponseBody`], by simply returning the body stream as is. +#[async_trait::async_trait] +impl DeserializeWith for ResponseBody { + async fn deserialize_with(body: ResponseBody) -> typespec::Result { + Ok(body) + } +} + +/// Implements [`DeserializeWith`] for an arbitrary type `D` +/// that implements [`serde::de::DeserializeOwned`] by deserializing the response body to the specified type using [`serde_json`]. +#[async_trait::async_trait] +impl DeserializeWith for D { + async fn deserialize_with(body: ResponseBody) -> typespec::Result { + body.json().await + } +} + +/// The default format used for deserialization. +/// +/// This format supports deserializing response bodies to: +/// * [`ResponseBody`] - The raw response body, without any deserialization. +/// * Any value implementing [`serde::de::DeserializeOwned`] - Deserializes the response body to the specified type using JSON deserialization. +pub struct DefaultFormat; + +impl Format for DefaultFormat {} + +/// A [`Format`] that deserializes response bodies using XML. +#[cfg(feature = "xml")] +pub struct XmlFormat; + +#[cfg(feature = "xml")] +impl Format for XmlFormat {} + +#[cfg(feature = "xml")] +#[async_trait::async_trait] +impl DeserializeWith for D { + async fn deserialize_with(body: ResponseBody) -> typespec::Result { + body.xml().await + } +} diff --git a/sdk/typespec/typespec_client_core/src/http/mod.rs b/sdk/typespec/typespec_client_core/src/http/mod.rs index 04dfecdae0..22c1508f09 100644 --- a/sdk/typespec/typespec_client_core/src/http/mod.rs +++ b/sdk/typespec/typespec_client_core/src/http/mod.rs @@ -5,6 +5,7 @@ mod clients; mod context; +mod format; pub mod headers; mod method; mod models; @@ -16,6 +17,7 @@ pub mod response; pub use clients::*; pub use context::*; +pub use format::*; pub use method::Method; pub use models::*; pub use options::*; diff --git a/sdk/typespec/typespec_client_core/src/http/response.rs b/sdk/typespec/typespec_client_core/src/http/response.rs index 0508d03cd1..2ae98610b3 100644 --- a/sdk/typespec/typespec_client_core/src/http/response.rs +++ b/sdk/typespec/typespec_client_core/src/http/response.rs @@ -3,11 +3,10 @@ //! HTTP responses. -use crate::http::{headers::Headers, StatusCode}; +use crate::http::{headers::Headers, DefaultFormat, Format, StatusCode}; use bytes::Bytes; use futures::{Stream, StreamExt}; use serde::de::DeserializeOwned; -use std::future::Future; use std::{fmt, marker::PhantomData, pin::Pin}; use typespec::error::{ErrorKind, ResultExt}; @@ -19,42 +18,6 @@ pub type PinnedStream = Pin> + Send + #[cfg(target_arch = "wasm32")] pub type PinnedStream = Pin>>>; -/// Trait that represents types that can be deserialized from an HTTP response body. -/// -/// [`Response`] is designed to work with values that may be serialized in various formats (JSON, XML, etc.). -/// In order to support that, the `T` provided must implement [`Model`], which provides the [`Model::from_response_body`] -/// method to deserialize the type from a response body. -pub trait Model: Sized { - /// Deserialize the response body into type `Self`. - /// - /// A [`ResponseBody`] represents a stream of bytes coming from the server. - /// The server may still be sending data, so it's up to implementors whether they want to wait for the entire body to be received or not. - /// For example, a type representing a simple REST API response will want to wait for the entire body to be received and then parse the body. - /// However, a type representing the download of a large file, may not want to do that and instead prepare to stream the body to a file or other destination. - #[cfg(not(target_arch = "wasm32"))] - fn from_response_body( - body: ResponseBody, - ) -> impl Future> + Send + Sync; - - #[cfg(target_arch = "wasm32")] - fn from_response_body(body: ResponseBody) -> impl Future>; -} - -// Allow for deserializing into "raw" JSON. -impl Model for serde_json::Value { - #[cfg(not(target_arch = "wasm32"))] - fn from_response_body( - body: ResponseBody, - ) -> impl Future> + Send + Sync { - body.json() - } - - #[cfg(target_arch = "wasm32")] - fn from_response_body(body: ResponseBody) -> impl Future> { - body.json() - } -} - /// An HTTP response. /// /// The type parameter `T` is a marker type that indicates what the caller should expect to be able to deserialize the body into. @@ -64,14 +27,14 @@ impl Model for serde_json::Value { /// Given a `Response`, a user can deserialize the body into the intended body type `T` by calling [`Response::into_body`]. /// However, because the type `T` is just a marker type, the user can also deserialize the body into a different type by calling [`Response::into_json_body`] or [`Response::into_xml_body`], /// or access the raw body using [`Response::into_raw_body`]. -pub struct Response { +pub struct Response { status: StatusCode, headers: Headers, body: ResponseBody, - phantom: PhantomData, + phantom: PhantomData<(T, F)>, } -impl Response { +impl Response { /// Create an HTTP response from an asynchronous stream of bytes. pub fn new(status: StatusCode, headers: Headers, stream: PinnedStream) -> Self { Self { @@ -114,108 +77,9 @@ impl Response { pub fn into_raw_body(self) -> ResponseBody { self.body } - - /// Fetches the entire body and tries to deserialize it as JSON into type `U`. - /// - /// This method is intended for situations where: - /// - /// 1. The response was not given a specific type by the service SDK e.g., the API returned `Response`, indicating a raw response. - /// 2. You want to deserialize the response into your OWN type, rather than the default type specified by the service SDK. - /// - /// # Example - /// ```rust - /// # pub struct GetSecretResponse { } - /// use typespec_client_core::http::{Model, Response, StatusCode}; - /// # #[cfg(not(feature = "derive"))] - /// # use typespec_macros::Model; - /// use serde::Deserialize; - /// use bytes::Bytes; - /// - /// #[derive(Model, Deserialize)] - /// struct MySecretResponse { - /// value: String, - /// } - /// - /// async fn parse_response(response: Response) { - /// // Calling `into_json_body` will parse the body into `MySecretResponse` instead of `GetSecretResponse`. - /// let my_struct: MySecretResponse = response.into_json_body().await.unwrap(); - /// assert_eq!("hunter2", my_struct.value); - /// } - /// - /// # #[tokio::main] - /// # async fn main() { - /// # let r: Response = typespec_client_core::http::Response::from_bytes( - /// # StatusCode::Ok, - /// # typespec_client_core::http::headers::Headers::new(), - /// # "{\"name\":\"database_password\",\"value\":\"hunter2\"}", - /// # ); - /// # parse_response(r).await; - /// # } - /// ``` - #[cfg(feature = "json")] - pub async fn into_json_body(self) -> crate::Result { - self.into_raw_body().json().await - } - - /// Fetches the entire body and tries to deserialize it as XML into type `U`. - /// - /// This method is intended for situations where: - /// - /// 1. The response was not given a specific type by the service SDK (i.e. the API returned `Response`, indicating a raw response). - /// 2. You want to deserialize the response into your OWN type, rather than the default type specified by the service SDK. - /// - /// # Example - /// ```rust - /// # pub struct GetSecretResponse { } - /// use typespec_client_core::http::{Model, Response, StatusCode}; - /// # #[cfg(not(feature = "derive"))] - /// # use typespec_macros::Model; - /// use serde::Deserialize; - /// use bytes::Bytes; - /// - /// #[derive(Model, Deserialize)] - /// struct MySecretResponse { - /// value: String, - /// } - /// - /// async fn parse_response(response: Response) { - /// // Calling `into_xml_body` will parse the body into `MySecretResponse` instead of `GetSecretResponse`. - /// let my_struct: MySecretResponse = response.into_xml_body().await.unwrap(); - /// assert_eq!("hunter2", my_struct.value); - /// } - /// - /// # #[tokio::main] - /// # async fn main() { - /// # let r: Response = typespec_client_core::http::Response::from_bytes( - /// # StatusCode::Ok, - /// # typespec_client_core::http::headers::Headers::new(), - /// # "database_passwordhunter2", - /// # ); - /// # parse_response(r).await; - /// # } - /// ``` - #[cfg(feature = "xml")] - pub async fn into_xml_body(self) -> crate::Result { - self.into_raw_body().xml().await - } } -impl Response { - /// Changes the type of the response body. - /// - /// Used to set the "type" of an untyped `Response`, transforming it into a `Response`. - pub(crate) fn with_default_deserialize_type(self) -> Response { - // This method name is a little clunky, but it's crate-local. If we ever decide it's useful outside this crate (which might happen), we can revisit the name. - Response { - status: self.status, - headers: self.headers, - body: self.body, - phantom: PhantomData, - } - } -} - -impl Response { +impl, F: Format> Response { /// Fetches the entire body and tries to convert it into type `T`. /// /// This is the preferred method for parsing the body of a service response into it's default model type. @@ -255,9 +119,7 @@ impl Response { /// assert_eq!(model.value, "hunter2"); /// # } /// ``` - pub async fn into_body(self) -> crate::Result { - T::from_response_body(self.body).await - } + pub async fn into_body(self) -> crate::Result {} } impl fmt::Debug for Response { From 47eff1ad2384a5c29e73c16c0d814b9eeb5bc23b Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Sat, 3 May 2025 14:32:54 +0000 Subject: [PATCH 02/11] remove Model and replace with Format type parameter --- sdk/core/azure_core/src/http/mod.rs | 2 +- .../examples/core_stream_response.rs | 8 +- .../typespec_client_core/src/http/mod.rs | 2 +- .../src/http/options/transport.rs | 12 +- .../typespec_client_core/src/http/pipeline.rs | 36 ++--- .../typespec_client_core/src/http/response.rs | 75 ++++----- sdk/typespec/typespec_macros/src/lib.rs | 63 +------- sdk/typespec/typespec_macros/src/model.rs | 144 ------------------ 8 files changed, 72 insertions(+), 270 deletions(-) delete mode 100644 sdk/typespec/typespec_macros/src/model.rs diff --git a/sdk/core/azure_core/src/http/mod.rs b/sdk/core/azure_core/src/http/mod.rs index 8dea60537f..cbf05ed773 100644 --- a/sdk/core/azure_core/src/http/mod.rs +++ b/sdk/core/azure_core/src/http/mod.rs @@ -17,7 +17,7 @@ pub use options::*; pub use pager::*; pub use pipeline::*; pub use request::{Body, Request, RequestContent}; -pub use response::{Model, Response}; +pub use response::Response; pub use typespec_client_core::http::response; pub use typespec_client_core::http::{ diff --git a/sdk/typespec/typespec_client_core/examples/core_stream_response.rs b/sdk/typespec/typespec_client_core/examples/core_stream_response.rs index 97e5de1f31..41f2c53b7f 100644 --- a/sdk/typespec/typespec_client_core/examples/core_stream_response.rs +++ b/sdk/typespec/typespec_client_core/examples/core_stream_response.rs @@ -40,25 +40,25 @@ mod client { use std::{cmp::min, task::Poll, time::Duration}; use tracing::debug; use typespec_client_core::{ - http::{headers::Headers, Model, Response, StatusCode}, + http::{headers::Headers, Response, StatusCode}, Bytes, }; - #[derive(Debug, Model, Deserialize)] + #[derive(Debug, Deserialize)] pub struct Team { pub name: Option, #[serde(default)] pub members: Vec, } - #[derive(Debug, Model, Deserialize)] + #[derive(Debug, Deserialize)] pub struct Person { pub id: u32, pub name: Option, } #[tracing::instrument] - pub fn get_binary_data() -> typespec_client_core::Result> { + pub fn get_binary_data() -> typespec_client_core::Result { let bytes = Bytes::from_static(b"Hello, world!"); let response = SlowResponse { bytes: bytes.repeat(5).into(), diff --git a/sdk/typespec/typespec_client_core/src/http/mod.rs b/sdk/typespec/typespec_client_core/src/http/mod.rs index 22c1508f09..85d88ed118 100644 --- a/sdk/typespec/typespec_client_core/src/http/mod.rs +++ b/sdk/typespec/typespec_client_core/src/http/mod.rs @@ -23,7 +23,7 @@ pub use models::*; pub use options::*; pub use pipeline::*; pub use request::{Body, Request, RequestContent}; -pub use response::{Model, Response}; +pub use response::Response; // Re-export important types. pub use typespec::http::StatusCode; diff --git a/sdk/typespec/typespec_client_core/src/http/options/transport.rs b/sdk/typespec/typespec_client_core/src/http/options/transport.rs index e071733941..8d76e84af9 100644 --- a/sdk/typespec/typespec_client_core/src/http/options/transport.rs +++ b/sdk/typespec/typespec_client_core/src/http/options/transport.rs @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -use crate::http::{clients, policies::Policy, Context, HttpClient, Request, Response}; +use crate::http::{ + clients, policies::Policy, Context, DeserializeWith, Format, HttpClient, Request, Response, +}; use std::sync::Arc; use typespec::error::Result; @@ -36,14 +38,18 @@ impl TransportOptions { } /// Use these options to send a request. - pub async fn send(&self, ctx: &Context<'_>, request: &mut Request) -> Result> { + pub async fn send, F: Format>( + &self, + ctx: &Context<'_>, + request: &mut Request, + ) -> Result> { use TransportOptionsImpl as I; let raw_response = match &self.inner { I::Http { http_client } => http_client.execute_request(request).await, I::Custom(s) => s.send(ctx, request, &[]).await, }; - raw_response.map(|r| r.with_default_deserialize_type()) + raw_response.map(|r| r.into_typed()) } } diff --git a/sdk/typespec/typespec_client_core/src/http/pipeline.rs b/sdk/typespec/typespec_client_core/src/http/pipeline.rs index 69a34a7a4c..d821796f5e 100644 --- a/sdk/typespec/typespec_client_core/src/http/pipeline.rs +++ b/sdk/typespec/typespec_client_core/src/http/pipeline.rs @@ -3,7 +3,7 @@ use crate::http::{ policies::{CustomHeadersPolicy, Policy, TransportPolicy}, - ClientOptions, Context, Request, Response, RetryOptions, + ClientOptions, Context, DeserializeWith, Format, Request, Response, RetryOptions, }; use std::sync::Arc; @@ -78,15 +78,15 @@ impl Pipeline { &self.pipeline } - pub async fn send( + pub async fn send, F: Format>( &self, ctx: &Context<'_>, request: &mut Request, - ) -> crate::Result> { + ) -> crate::Result> { self.pipeline[0] .send(ctx, request, &self.pipeline[1..]) .await - .map(|resp| resp.with_default_deserialize_type()) + .map(|r| r.into_typed()) } } @@ -99,7 +99,6 @@ mod tests { }; use bytes::Bytes; use serde::Deserialize; - use typespec_macros::Model; #[tokio::test] async fn deserializes_response() { @@ -122,27 +121,24 @@ mod tests { } } - #[derive(Model, Debug, Deserialize)] - #[typespec(crate = "crate")] + #[derive(Debug, Deserialize)] struct Model { foo: i32, bar: String, } - let options = ClientOptions { - transport: Some(TransportOptions::new_custom_policy(Arc::new(Responder {}))), - ..Default::default() - }; - let pipeline = Pipeline::new(options, Vec::new(), Vec::new()); + // Simulated service method + async fn service_method() -> crate::Result> { + let options = ClientOptions { + transport: Some(TransportOptions::new_custom_policy(Arc::new(Responder {}))), + ..Default::default() + }; + let pipeline = Pipeline::new(options, Vec::new(), Vec::new()); + let mut request = Request::new("http://localhost".parse().unwrap(), Method::Get); + pipeline.send(&Context::default(), &mut request).await + } - let mut request = Request::new("http://localhost".parse().unwrap(), Method::Get); - let model: Model = pipeline - .send(&Context::default(), &mut request) - .await - .unwrap() - .into_body() - .await - .unwrap(); + let model = service_method().await.unwrap().into_body().await.unwrap(); assert_eq!(1, model.foo); assert_eq!("baz", &model.bar); diff --git a/sdk/typespec/typespec_client_core/src/http/response.rs b/sdk/typespec/typespec_client_core/src/http/response.rs index 2ae98610b3..1c469a498f 100644 --- a/sdk/typespec/typespec_client_core/src/http/response.rs +++ b/sdk/typespec/typespec_client_core/src/http/response.rs @@ -3,16 +3,13 @@ //! HTTP responses. -use crate::http::{headers::Headers, DefaultFormat, Format, StatusCode}; +use crate::http::{headers::Headers, DefaultFormat, DeserializeWith, Format, StatusCode}; use bytes::Bytes; use futures::{Stream, StreamExt}; use serde::de::DeserializeOwned; use std::{fmt, marker::PhantomData, pin::Pin}; use typespec::error::{ErrorKind, ResultExt}; -#[cfg(feature = "derive")] -pub use typespec_macros::Model; - #[cfg(not(target_arch = "wasm32"))] pub type PinnedStream = Pin> + Send + Sync>>; #[cfg(target_arch = "wasm32")] @@ -27,14 +24,32 @@ pub type PinnedStream = Pin>>>; /// Given a `Response`, a user can deserialize the body into the intended body type `T` by calling [`Response::into_body`]. /// However, because the type `T` is just a marker type, the user can also deserialize the body into a different type by calling [`Response::into_json_body`] or [`Response::into_xml_body`], /// or access the raw body using [`Response::into_raw_body`]. -pub struct Response { +pub struct Response { status: StatusCode, headers: Headers, body: ResponseBody, phantom: PhantomData<(T, F)>, } -impl Response { +impl Response { + /// Converts an "untyped" raw response into a typed response, using the specified format. + /// + /// This method is intended for use in service clients, to "set" the model type for a raw response receieved from the pipeline. + pub fn into_typed(self) -> Response + where + T: DeserializeWith, + F2: Format, + { + Response { + status: self.status, + headers: self.headers, + body: self.body, + phantom: PhantomData, + } + } +} + +impl Response { /// Create an HTTP response from an asynchronous stream of bytes. pub fn new(status: StatusCode, headers: Headers, stream: PinnedStream) -> Self { Self { @@ -79,7 +94,7 @@ impl Response { } } -impl, F: Format> Response { +impl, F: Format> Response { /// Fetches the entire body and tries to convert it into type `T`. /// /// This is the preferred method for parsing the body of a service response into it's default model type. @@ -87,10 +102,8 @@ impl, F: Format> Response { /// # Example /// ```rust /// # use serde::Deserialize; - /// # use typespec_client_core::http::{Model, StatusCode}; - /// # #[cfg(not(feature = "derive"))] - /// # use typespec_macros::Model; - /// # #[derive(Model, Deserialize)] + /// # use typespec_client_core::http::StatusCode; + /// # #[derive(Deserialize)] /// # pub struct GetSecretResponse { /// # name: String, /// # value: String, @@ -119,10 +132,12 @@ impl, F: Format> Response { /// assert_eq!(model.value, "hunter2"); /// # } /// ``` - pub async fn into_body(self) -> crate::Result {} + pub async fn into_body(self) -> crate::Result { + T::deserialize_with(self.body).await + } } -impl fmt::Debug for Response { +impl fmt::Debug for Response { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Response") .field("status", &self.status) @@ -211,16 +226,12 @@ impl fmt::Debug for ResponseBody { #[cfg(test)] mod tests { use crate::http::headers::Headers; - use crate::http::{response::ResponseBody, Model, Response, StatusCode}; + use crate::http::{Response, StatusCode}; #[tokio::test] - pub async fn can_extract_raw_body_regardless_of_t() -> Result<(), Box> { + pub async fn can_extract_raw_body_regardless_of_t_or_f( + ) -> Result<(), Box> { pub struct MyModel; - impl Model for MyModel { - async fn from_response_body(_body: ResponseBody) -> crate::Result { - panic!("Should never be called in this test"); - } - } { let response_raw: Response = @@ -231,8 +242,7 @@ mod tests { { let response_t: Response = - Response::from_bytes(StatusCode::Ok, Headers::new(), b"Hello".as_slice()) - .with_default_deserialize_type(); + Response::from_bytes(StatusCode::Ok, Headers::new(), b"Hello".as_slice()); let body = response_t.into_raw_body(); assert_eq!(b"Hello", &*body.collect().await?); } @@ -245,19 +255,16 @@ mod tests { use crate::http::Response; use crate::http::StatusCode; use serde::Deserialize; - use typespec_macros::Model; /// An example JSON-serialized response type. - #[derive(Model, Deserialize)] - #[typespec(crate = "crate")] + #[derive(Deserialize)] struct GetSecretResponse { name: String, value: String, } /// An example JSON-serialized list response type. - #[derive(Model, Deserialize)] - #[typespec(crate = "crate")] + #[derive(Deserialize)] struct GetSecretListResponse { value: Vec, #[serde(rename = "nextLink")] @@ -301,7 +308,7 @@ mod tests { } let response = get_secret(); - let secret: MySecretResponse = response.into_json_body().await.unwrap(); + let secret: MySecretResponse = response.into_raw_body().json().await.unwrap(); assert_eq!(secret.yon_name, "my_secret"); assert_eq!(secret.yon_value, "my_value"); } @@ -334,20 +341,18 @@ mod tests { use crate::http::headers::Headers; use crate::http::Response; use crate::http::StatusCode; + use crate::http::XmlFormat; use serde::Deserialize; - use typespec_macros::Model; /// An example XML-serialized response type. - #[derive(Model, Deserialize)] - #[typespec(crate = "crate")] - #[typespec(format = "xml")] + #[derive(Deserialize)] struct GetSecretResponse { name: String, value: String, } /// A sample service client function. - fn get_secret() -> Response { + fn get_secret() -> Response { Response::from_bytes( StatusCode::Ok, Headers::new(), @@ -373,8 +378,8 @@ mod tests { yon_value: String, } - let response = get_secret(); - let secret: MySecretResponse = response.into_xml_body().await.unwrap(); + let response: Response = get_secret(); + let secret: MySecretResponse = response.into_raw_body().xml().await.unwrap(); assert_eq!(secret.yon_name, "my_secret"); assert_eq!(secret.yon_value, "my_value"); } diff --git a/sdk/typespec/typespec_macros/src/lib.rs b/sdk/typespec/typespec_macros/src/lib.rs index 157a501b80..f6071cf908 100644 --- a/sdk/typespec/typespec_macros/src/lib.rs +++ b/sdk/typespec/typespec_macros/src/lib.rs @@ -1,11 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -use syn::{parse::ParseStream, parse_macro_input, spanned::Spanned, DeriveInput, Error, LitStr}; +use syn::{parse_macro_input, DeriveInput}; extern crate proc_macro; -mod model; mod safe_debug; type Result = ::std::result::Result; @@ -25,66 +24,6 @@ fn run_derive_macro(input: proc_macro::TokenStream, imp: DeriveImpl) -> proc_mac } } -/// Parses a `syn::parse::ParseStream` that is expected to contain a string literal and extracts the `syn::LitStr`. -fn parse_literal_string(value: ParseStream) -> Result { - let expr: syn::Expr = value - .parse() - .map_err(|_| Error::new(value.span(), "expected string literal"))?; - match expr { - syn::Expr::Lit(lit) => match lit.lit { - syn::Lit::Str(s) => Ok(s), - _ => Err(Error::new(lit.span(), "expected string literal")), - }, - _ => Err(Error::new(expr.span(), "expected string literal")), - } -} - -/// Derive macro for implementing the `Model` trait. -/// -/// Deriving this trait allows a type to be deserialized from an HTTP response body. -/// By default, the type must also implement `serde::Deserialize`, or the generated code will not compile. -/// -/// ## Attributes -/// -/// The following attributes are supported on the struct itself: -/// -/// ### `#[typespec(format)]` -/// -/// The format attribute specifies the format of the response body. The default is `json`. -/// If compiling with the `xml` feature, the value `xml` is also supported. -/// -/// ```rust -/// # use typespec_macros::Model; -/// # use serde::Deserialize; -/// #[derive(Model, Deserialize)] -/// #[typespec(format = "xml")] -/// struct MyModel { -/// value: String -/// } -/// ``` -/// -/// **NOTE:** Using formats other than JSON may require enabling additional features in `typespec_client_core`. -/// -/// ### `#[typespec(crate)]` -/// -/// The 'crate' attribute specifies an alternate module path, other than the default of `typespec_client_core`, to reference the typespec client crate. -/// -/// ```rust -/// # use typespec_macros::Model; -/// # use serde::Deserialize; -/// extern crate typespec_client_core as my_typespec; -/// -/// #[derive(Model, Deserialize)] -/// #[typespec(crate = "my_typespec")] -/// struct MyModel { -/// value: String -/// } -/// ``` -#[proc_macro_derive(Model, attributes(typespec))] -pub fn derive_model(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - run_derive_macro(input, model::derive_model_impl) -} - /// Derive to help prevent leaking personally identifiable information (PII) that deriving [`Debug`](std::fmt::Debug) might otherwise. /// /// `SafeDebug` is not a trait and cannot be implemented, nor should you derive `Debug` explicitly. diff --git a/sdk/typespec/typespec_macros/src/model.rs b/sdk/typespec/typespec_macros/src/model.rs deleted file mode 100644 index 81362f892e..0000000000 --- a/sdk/typespec/typespec_macros/src/model.rs +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -use proc_macro2::TokenStream; -use syn::spanned::Spanned; -use syn::{Attribute, DeriveInput, Error, Meta, Path}; - -use crate::{parse_literal_string, Result}; - -pub fn derive_model_impl(ast: DeriveInput) -> Result { - let body = generate_body(ast)?; - - // We wrap the generated code in a const block to give it a unique scope. - let gen = quote::quote! { - #[doc(hidden)] - const _: () = { - #body - }; - }; - Ok(gen) -} - -fn generate_body(ast: DeriveInput) -> Result { - let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); - let name = &ast.ident; - - // Parse attributes - let attrs = Attrs::from_attrs(&ast.attrs)?; - - let format = attrs.format.unwrap_or(Format::Json); - let deserialize_body = match format { - Format::Json => quote::quote! { - body.json().await - }, - Format::Xml => quote::quote! { - body.xml().await - }, - }; - - // If the standard path is used, we need to add 'extern crate', because it's possible the calling code - // depends on typespec_client_core transitively, which means it's not in scope by default. - // That's not necessary when using a custom path because we assume the user has done that work. - let typespec_import = match attrs.typespec_path { - Some(path) => quote::quote! { - use #path as _typespec_client_core; - }, - None => quote::quote! { - #[allow(unused_extern_crates, clippy::useless_attribute)] - extern crate typespec_client_core as _typespec_client_core; - }, - }; - - Ok(quote::quote! { - #typespec_import - - #[automatically_derived] - impl #impl_generics _typespec_client_core::http::Model for #name #ty_generics #where_clause { - async fn from_response_body(body: _typespec_client_core::http::response::ResponseBody) -> _typespec_client_core::Result { - #deserialize_body - } - } - }) -} - -enum Format { - Json, - Xml, -} - -struct Attrs { - pub typespec_path: Option, - pub format: Option, -} - -impl Attrs { - pub fn from_attrs(attributes: &[Attribute]) -> Result { - let mut attrs = Attrs { - typespec_path: None, - format: None, - }; - - let mut result = Ok(()); - for attribute in attributes.iter().filter(|a| a.path().is_ident("typespec")) { - result = match (result, parse_attr(attribute, &mut attrs)) { - (Ok(()), Err(e)) => Err(e), - (Err(mut e1), Err(e2)) => { - e1.combine(e2); - Err(e1) - } - (e, Ok(())) => e, - }; - } - - result.map(|_| attrs) - } -} - -const INVALID_TYPESPEC_ATTRIBUTE_MESSAGE: &str = - "invalid typespec attribute, expected attribute in form #[typespec(key = value)]"; - -fn parse_attr(attribute: &Attribute, attrs: &mut Attrs) -> Result<()> { - let Meta::List(meta_list) = &attribute.meta else { - return Err(Error::new( - attribute.span(), - INVALID_TYPESPEC_ATTRIBUTE_MESSAGE, - )); - }; - - meta_list.parse_nested_meta(|meta| { - let ident = meta - .path - .get_ident() - .ok_or_else(|| Error::new(attribute.span(), INVALID_TYPESPEC_ATTRIBUTE_MESSAGE))?; - let value = meta - .value() - .map_err(|_| Error::new(attribute.span(), INVALID_TYPESPEC_ATTRIBUTE_MESSAGE))?; - - match ident.to_string().as_str() { - "crate" => { - let lit = parse_literal_string(value)?; - let path = lit.parse().map_err(|_| { - Error::new(lit.span(), format!("invalid module path: {}", lit.value())) - })?; - attrs.typespec_path = Some(path); - Ok(()) - } - "format" => { - let lit = parse_literal_string(value)?; - attrs.format = Some(match lit.value().as_str() { - "json" => Format::Json, - "xml" => Format::Xml, - x => { - return Err(Error::new(lit.span(), format!("Unknown format '{}'", x))); - } - }); - Ok(()) - } - x => Err(Error::new( - meta.path.span(), - format!("unknown typespec attribute '#[typespec({})'", x), - )), - } - }) -} From ed917953fe31320fb6439e665b9ac24ab89a355a Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Mon, 5 May 2025 17:44:11 +0000 Subject: [PATCH 03/11] fix issues in azure_core, azure_identity, and azure_data_cosmos --- sdk/core/azure_core_test/src/proxy/client.rs | 4 ++-- sdk/cosmos/azure_data_cosmos/src/feed.rs | 2 +- .../src/models/container_properties.rs | 3 +-- .../azure_data_cosmos/src/models/mod.rs | 22 +++++-------------- .../src/models/patch_operations.rs | 4 ++-- .../src/models/throughput_properties.rs | 7 ++---- .../src/azure_pipelines_credential.rs | 2 +- sdk/identity/azure_identity/src/lib.rs | 8 +++---- .../azure_identity/src/refresh_token.rs | 5 ++++- .../typespec_client_core/src/http/pipeline.rs | 8 ++++--- .../typespec_client_core/src/http/response.rs | 6 +---- 11 files changed, 28 insertions(+), 43 deletions(-) diff --git a/sdk/core/azure_core_test/src/proxy/client.rs b/sdk/core/azure_core_test/src/proxy/client.rs index 37c5bd16cf..8f69feae34 100644 --- a/sdk/core/azure_core_test/src/proxy/client.rs +++ b/sdk/core/azure_core_test/src/proxy/client.rs @@ -115,7 +115,7 @@ impl Client { .send::(&ctx, &mut request) .await?; let recording_id = resp.headers().get_str(&RECORDING_ID)?.to_string(); - let mut result: PlaybackStartResult = resp.into_json_body().await?; + let mut result: PlaybackStartResult = resp.into_body().await?; result.recording_id = recording_id; Ok(result) } @@ -212,7 +212,7 @@ impl Client { self.pipeline .send::(&ctx, &mut request) .await? - .into_json_body() + .into_body() .await } diff --git a/sdk/cosmos/azure_data_cosmos/src/feed.rs b/sdk/cosmos/azure_data_cosmos/src/feed.rs index b504563acc..2a464b341e 100644 --- a/sdk/cosmos/azure_data_cosmos/src/feed.rs +++ b/sdk/cosmos/azure_data_cosmos/src/feed.rs @@ -78,7 +78,7 @@ impl FeedPage { pub(crate) async fn from_response(response: Response) -> azure_core::Result { let headers = response.headers().clone(); let continuation = headers.get_optional_string(&constants::CONTINUATION); - let body: FeedBody = response.into_json_body::>().await?; + let body: FeedBody = response.into_raw_body().json().await?; Ok(Self { items: body.items, diff --git a/sdk/cosmos/azure_data_cosmos/src/models/container_properties.rs b/sdk/cosmos/azure_data_cosmos/src/models/container_properties.rs index 2f00d390a5..b023bfe922 100644 --- a/sdk/cosmos/azure_data_cosmos/src/models/container_properties.rs +++ b/sdk/cosmos/azure_data_cosmos/src/models/container_properties.rs @@ -3,7 +3,6 @@ use std::{borrow::Cow, time::Duration}; -use azure_core::http::response::Model; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use crate::models::{IndexingPolicy, PartitionKeyDefinition, SystemProperties}; @@ -48,7 +47,7 @@ where /// Also, note that the `id` and `partition_key` values are **required** by the server. You will get an error from the server if you omit them. /// /// [Struct Update]: https://doc.rust-lang.org/stable/book/ch05-01-defining-structs.html?highlight=Struct#creating-instances-from-other-instances-with-struct-update-syntax -#[derive(Model, Clone, Default, Debug, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Clone, Default, Debug, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct ContainerProperties { /// The ID of the container. diff --git a/sdk/cosmos/azure_data_cosmos/src/models/mod.rs b/sdk/cosmos/azure_data_cosmos/src/models/mod.rs index e2b3c5bd7b..b7e8072060 100644 --- a/sdk/cosmos/azure_data_cosmos/src/models/mod.rs +++ b/sdk/cosmos/azure_data_cosmos/src/models/mod.rs @@ -3,14 +3,8 @@ //! Model types sent to and received from the Azure Cosmos DB API. -use azure_core::{ - date::OffsetDateTime, - http::{ - response::{Model, ResponseBody}, - Etag, - }, -}; -use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize}; +use azure_core::{date::OffsetDateTime, http::Etag}; +use serde::{Deserialize, Deserializer, Serialize}; mod container_properties; mod indexing_policy; @@ -51,15 +45,9 @@ pub struct QueryResults { pub items: Vec, } -impl Model for QueryResults { - async fn from_response_body(body: ResponseBody) -> typespec_client_core::Result { - body.json().await - } -} - /// A page of results from [`CosmosClient::query_databases`](crate::CosmosClient::query_databases()) #[non_exhaustive] -#[derive(Clone, Default, Debug, Deserialize, Model)] +#[derive(Clone, Default, Debug, Deserialize)] pub struct DatabaseQueryResults { #[serde(alias = "Databases")] pub databases: Vec, @@ -67,7 +55,7 @@ pub struct DatabaseQueryResults { /// A page of results from [`DatabaseClient::query_containers`](crate::clients::DatabaseClient::query_containers()) #[non_exhaustive] -#[derive(Clone, Default, Debug, Deserialize, Model)] +#[derive(Clone, Default, Debug, Deserialize)] pub struct ContainerQueryResults { #[serde(alias = "DocumentCollections")] pub containers: Vec, @@ -108,7 +96,7 @@ pub struct SystemProperties { /// /// Returned by [`DatabaseClient::read()`](crate::clients::DatabaseClient::read()). #[non_exhaustive] -#[derive(Model, Clone, Default, Debug, Deserialize, PartialEq, Eq)] +#[derive(Clone, Default, Debug, Deserialize, PartialEq, Eq)] pub struct DatabaseProperties { /// The ID of the database. pub id: String, diff --git a/sdk/cosmos/azure_data_cosmos/src/models/patch_operations.rs b/sdk/cosmos/azure_data_cosmos/src/models/patch_operations.rs index 388b77454b..20e42d27c0 100644 --- a/sdk/cosmos/azure_data_cosmos/src/models/patch_operations.rs +++ b/sdk/cosmos/azure_data_cosmos/src/models/patch_operations.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use azure_core::{error::ErrorKind, http::response::Model, Error}; +use azure_core::{error::ErrorKind, Error}; use serde::{Deserialize, Serialize}; // Cosmos' patch operations are _similar_ to JSON Patch (RFC 6902) in structure, but have different operations. @@ -37,7 +37,7 @@ use serde::{Deserialize, Serialize}; /// # Ok(()) /// # } /// ``` -#[derive(Model, Default, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Eq)] pub struct PatchDocument { pub operations: Vec, } diff --git a/sdk/cosmos/azure_data_cosmos/src/models/throughput_properties.rs b/sdk/cosmos/azure_data_cosmos/src/models/throughput_properties.rs index 240f677bb0..2372f6c9ba 100644 --- a/sdk/cosmos/azure_data_cosmos/src/models/throughput_properties.rs +++ b/sdk/cosmos/azure_data_cosmos/src/models/throughput_properties.rs @@ -3,17 +3,14 @@ use std::borrow::Cow; -use azure_core::http::{ - headers::{AsHeaders, HeaderName, HeaderValue}, - response::Model, -}; +use azure_core::http::headers::{AsHeaders, HeaderName, HeaderValue}; use serde::{Deserialize, Serialize}; use crate::{constants, models::SystemProperties}; const OFFER_VERSION_2: &str = "V2"; -#[derive(Model, Clone, Default, Deserialize, Serialize)] +#[derive(Clone, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ThroughputProperties { resource: String, diff --git a/sdk/identity/azure_identity/src/azure_pipelines_credential.rs b/sdk/identity/azure_identity/src/azure_pipelines_credential.rs index add84581e3..4a908061de 100644 --- a/sdk/identity/azure_identity/src/azure_pipelines_credential.rs +++ b/sdk/identity/azure_identity/src/azure_pipelines_credential.rs @@ -146,7 +146,7 @@ impl ClientAssertion for Client { ); } - let assertion: Assertion = resp.into_json_body().await?; + let assertion: Assertion = resp.into_raw_body().json().await?; Ok(assertion.oidc_token.secret().to_string()) } } diff --git a/sdk/identity/azure_identity/src/lib.rs b/sdk/identity/azure_identity/src/lib.rs index f991109cfc..9e990edd35 100644 --- a/sdk/identity/azure_identity/src/lib.rs +++ b/sdk/identity/azure_identity/src/lib.rs @@ -27,15 +27,14 @@ pub use credentials::*; pub use managed_identity_credential::*; use serde::Deserialize; use std::borrow::Cow; -use typespec_client_core::http::Model; -#[derive(Debug, Default, Deserialize, Model)] +#[derive(Debug, Default, Deserialize)] #[serde(default)] struct EntraIdErrorResponse { error_description: String, } -#[derive(Debug, Default, Deserialize, Model)] +#[derive(Debug, Default, Deserialize)] #[serde(default)] struct EntraIdTokenResponse { token_type: String, @@ -49,7 +48,8 @@ where T: serde::de::DeserializeOwned, { let t: T = res - .into_json_body() + .into_raw_body() + .json() .await .with_context(ErrorKind::Credential, || { format!( diff --git a/sdk/identity/azure_identity/src/refresh_token.rs b/sdk/identity/azure_identity/src/refresh_token.rs index 46a63e7619..19cba611dd 100644 --- a/sdk/identity/azure_identity/src/refresh_token.rs +++ b/sdk/identity/azure_identity/src/refresh_token.rs @@ -55,7 +55,10 @@ pub async fn exchange( let rsp_status = rsp.status(); if rsp_status.is_success() { - rsp.into_json_body().await.map_kind(ErrorKind::Credential) + rsp.into_raw_body() + .json() + .await + .map_kind(ErrorKind::Credential) } else { let rsp_body = rsp.into_raw_body().collect().await?; let token_error: RefreshTokenError = diff --git a/sdk/typespec/typespec_client_core/src/http/pipeline.rs b/sdk/typespec/typespec_client_core/src/http/pipeline.rs index d821796f5e..4372d5eb25 100644 --- a/sdk/typespec/typespec_client_core/src/http/pipeline.rs +++ b/sdk/typespec/typespec_client_core/src/http/pipeline.rs @@ -3,10 +3,12 @@ use crate::http::{ policies::{CustomHeadersPolicy, Policy, TransportPolicy}, - ClientOptions, Context, DeserializeWith, Format, Request, Response, RetryOptions, + ClientOptions, Context, Request, Response, RetryOptions, }; use std::sync::Arc; +use super::DefaultFormat; + /// Execution pipeline. /// /// A pipeline follows a precise flow: @@ -78,11 +80,11 @@ impl Pipeline { &self.pipeline } - pub async fn send, F: Format>( + pub async fn send( &self, ctx: &Context<'_>, request: &mut Request, - ) -> crate::Result> { + ) -> crate::Result> { self.pipeline[0] .send(ctx, request, &self.pipeline[1..]) .await diff --git a/sdk/typespec/typespec_client_core/src/http/response.rs b/sdk/typespec/typespec_client_core/src/http/response.rs index 1c469a498f..1e1db742c1 100644 --- a/sdk/typespec/typespec_client_core/src/http/response.rs +++ b/sdk/typespec/typespec_client_core/src/http/response.rs @@ -35,11 +35,7 @@ impl Response { /// Converts an "untyped" raw response into a typed response, using the specified format. /// /// This method is intended for use in service clients, to "set" the model type for a raw response receieved from the pipeline. - pub fn into_typed(self) -> Response - where - T: DeserializeWith, - F2: Format, - { + pub fn into_typed(self) -> Response { Response { status: self.status, headers: self.headers, From b8a84a2d65751629f3bb2e0baaef720d710593a0 Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Mon, 5 May 2025 20:44:18 +0000 Subject: [PATCH 04/11] fix tests in hand-written crates --- sdk/core/azure_core/src/http/pager.rs | 7 +- sdk/cosmos/azure_data_cosmos/README.md | 15 +- .../examples/cosmos/create.rs | 2 +- .../examples/cosmos/patch.rs | 2 +- .../azure_data_cosmos/examples/cosmos/read.rs | 2 +- .../examples/cosmos/replace.rs | 2 +- .../examples/cosmos/upsert.rs | 2 +- .../src/clients/container_client.rs | 22 +- .../azure_data_cosmos/tests/cosmos_items.rs | 30 ++- .../client_certificate_credentials.rs | 2 +- .../src/http/options/transport.rs | 2 +- .../typespec_client_core/src/http/pipeline.rs | 13 +- .../typespec_client_core/src/http/response.rs | 14 +- .../tests/compilation-tests.rs | 230 ------------------ .../tests/data/compilation-tests/.gitignore | 1 - .../tests/data/compilation-tests/Cargo.toml | 18 -- .../data/compilation-tests/src/.gitignore | 2 - .../tests/data/compilation-tests/src/lib.rs | 1 - .../src/model/bad_attributes.expected.json | 90 ------- .../src/model/bad_attributes.rs | 37 --- .../data/compilation-tests/src/model/mod.rs | 3 - .../not_derive_deserialize.expected.json | 13 - .../src/model/not_derive_deserialize.rs | 7 - .../src/model/unknown_format.expected.json | 13 - .../src/model/unknown_format.rs | 9 - 25 files changed, 71 insertions(+), 468 deletions(-) delete mode 100644 sdk/typespec/typespec_macros/tests/compilation-tests.rs delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/.gitignore delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/Cargo.toml delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/src/.gitignore delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/src/lib.rs delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.expected.json delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/mod.rs delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/not_derive_deserialize.expected.json delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/not_derive_deserialize.rs delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/unknown_format.expected.json delete mode 100644 sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/unknown_format.rs diff --git a/sdk/core/azure_core/src/http/pager.rs b/sdk/core/azure_core/src/http/pager.rs index 77af7a3b38..17462a900b 100644 --- a/sdk/core/azure_core/src/http/pager.rs +++ b/sdk/core/azure_core/src/http/pager.rs @@ -150,7 +150,6 @@ enum State { mod tests { use std::collections::HashMap; - use crate::http::Model; use futures::StreamExt; use serde::Deserialize; @@ -161,8 +160,7 @@ mod tests { #[tokio::test] pub async fn standard_pagination() { - #[derive(Model, Deserialize, Debug, PartialEq, Eq)] - #[typespec(crate = "crate")] + #[derive(Deserialize, Debug, PartialEq, Eq)] struct Page { pub page: usize, } @@ -233,8 +231,7 @@ mod tests { #[tokio::test] pub async fn error_stops_pagination() { - #[derive(Model, Deserialize, Debug, PartialEq, Eq)] - #[typespec(crate = "crate")] + #[derive(Deserialize, Debug, PartialEq, Eq)] struct Page { pub page: usize, } diff --git a/sdk/cosmos/azure_data_cosmos/README.md b/sdk/cosmos/azure_data_cosmos/README.md index a9447c04ef..fdf8cf175b 100644 --- a/sdk/cosmos/azure_data_cosmos/README.md +++ b/sdk/cosmos/azure_data_cosmos/README.md @@ -1,4 +1,4 @@ -# Azure Cosmos DB SDK for Rust. +# Azure Cosmos DB SDK for Rust This client library enables client applications to connect to Azure Cosmos DB via the NoSQL API. Azure Cosmos DB is a globally distributed, multi-model database service. @@ -19,7 +19,7 @@ cargo add azure_data_cosmos * An [Azure subscription] or free Azure Cosmos DB trial account. Note: If you don't have an Azure subscription, create a free account before you begin. -You can Try Azure Cosmos DB for free without an Azure subscription, free of charge and commitments, or create an Azure Cosmos DB free tier account, with the first 400 RU/s and 5 GB of storage for free. You can also use the Azure Cosmos DB Emulator with a URI of https://localhost:8081. For the key to use with the emulator, see [how to develop with the emulator](https://learn.microsoft.com/azure/cosmos-db/how-to-develop-emulator). +You can Try Azure Cosmos DB for free without an Azure subscription, free of charge and commitments, or create an Azure Cosmos DB free tier account, with the first 400 RU/s and 5 GB of storage for free. You can also use the Azure Cosmos DB Emulator with a URI of . For the key to use with the emulator, see [how to develop with the emulator](https://learn.microsoft.com/azure/cosmos-db/how-to-develop-emulator). ### Create an Azure Cosmos DB account @@ -36,6 +36,7 @@ In order to interact with the Azure Cosmos DB service you'll need to create an i ## Examples The following section provides several code snippets covering some of the most common Azure Cosmos DB NoSQL API tasks, including: + * [Create Client](#create-cosmos-db-client "Create Cosmos DB client") * [CRUD operation on Items](#crud-operation-on-items "CRUD operation on Items") @@ -103,7 +104,7 @@ async fn example(cosmos_client: CosmosClient) -> Result<(), Box Result<(), Box().await?; + let created: serde_json::Value = response.into_raw_body().json().await?; println!("Newly created item:"); println!("{:#?}", created); } diff --git a/sdk/cosmos/azure_data_cosmos/examples/cosmos/patch.rs b/sdk/cosmos/azure_data_cosmos/examples/cosmos/patch.rs index 59178953e0..ef90508f9a 100644 --- a/sdk/cosmos/azure_data_cosmos/examples/cosmos/patch.rs +++ b/sdk/cosmos/azure_data_cosmos/examples/cosmos/patch.rs @@ -48,7 +48,7 @@ impl PatchCommand { match response { Err(e) if e.http_status() == Some(StatusCode::NotFound) => println!("Item not found!"), Ok(r) => { - let item: serde_json::Value = r.into_json_body().await?; + let item: serde_json::Value = r.into_raw_body().json().await?; println!("Patched item:"); println!("{:#?}", item); } diff --git a/sdk/cosmos/azure_data_cosmos/examples/cosmos/read.rs b/sdk/cosmos/azure_data_cosmos/examples/cosmos/read.rs index 0abf474235..03d9604076 100644 --- a/sdk/cosmos/azure_data_cosmos/examples/cosmos/read.rs +++ b/sdk/cosmos/azure_data_cosmos/examples/cosmos/read.rs @@ -61,7 +61,7 @@ impl ReadCommand { println!("Item not found!") } Ok(r) => { - let item: serde_json::Value = r.into_json_body().await?; + let item: serde_json::Value = r.into_body().await?; println!("Found item:"); println!("{:#?}", item); } diff --git a/sdk/cosmos/azure_data_cosmos/examples/cosmos/replace.rs b/sdk/cosmos/azure_data_cosmos/examples/cosmos/replace.rs index 75a8a9259a..1766fd8253 100644 --- a/sdk/cosmos/azure_data_cosmos/examples/cosmos/replace.rs +++ b/sdk/cosmos/azure_data_cosmos/examples/cosmos/replace.rs @@ -90,7 +90,7 @@ impl ReplaceCommand { println!("Replaced item successfully"); if show_updated { - let created: serde_json::Value = r.into_json_body().await?; + let created: serde_json::Value = r.into_raw_body().json().await?; println!("Newly replaced item:"); println!("{:#?}", created); } diff --git a/sdk/cosmos/azure_data_cosmos/examples/cosmos/upsert.rs b/sdk/cosmos/azure_data_cosmos/examples/cosmos/upsert.rs index 029cc6e67a..f85efe1269 100644 --- a/sdk/cosmos/azure_data_cosmos/examples/cosmos/upsert.rs +++ b/sdk/cosmos/azure_data_cosmos/examples/cosmos/upsert.rs @@ -44,7 +44,7 @@ impl UpsertCommand { println!("Item updated successfully"); if self.show_updated { - let created: serde_json::Value = response.into_json_body().await?; + let created: serde_json::Value = response.into_raw_body().json().await?; println!("Updated item:"); println!("{:#?}", created); } diff --git a/sdk/cosmos/azure_data_cosmos/src/clients/container_client.rs b/sdk/cosmos/azure_data_cosmos/src/clients/container_client.rs index 0e3a201c2d..188b902bda 100644 --- a/sdk/cosmos/azure_data_cosmos/src/clients/container_client.rs +++ b/sdk/cosmos/azure_data_cosmos/src/clients/container_client.rs @@ -216,7 +216,7 @@ impl ContainerClient { /// /// By default, the newly created item is *not* returned in the HTTP response. /// If you want the new item to be returned, set the [`ItemOptions::enable_content_response_on_write`] option to `true`. - /// You can deserialize the returned item using [`Response::into_json_body`], like this: + /// You can deserialize the returned item using [`ResponseBody::json`](azure_core::http::response::ResponseBody::json), like this: /// /// ```rust,no_run /// use azure_data_cosmos::ItemOptions; @@ -242,7 +242,7 @@ impl ContainerClient { /// let created_item = container_client /// .create_item("category1", p, Some(options)) /// .await? - /// .into_json_body::() + /// .into_raw_body().json::() /// .await?; /// # Ok(()) /// # } @@ -306,7 +306,7 @@ impl ContainerClient { /// /// By default, the replaced item is *not* returned in the HTTP response. /// If you want the replaced item to be returned, set the [`ItemOptions::enable_content_response_on_write`] option to `true`. - /// You can deserialize the returned item using [`Response::into_json_body`], like this: + /// You can deserialize the returned item using [`ResponseBody::json`](azure_core::http::response::ResponseBody::json), like this: /// /// ```rust,no_run /// use azure_data_cosmos::ItemOptions; @@ -332,7 +332,7 @@ impl ContainerClient { /// let updated_product: Product = container_client /// .replace_item("category1", "product1", p, Some(options)) /// .await? - /// .into_json_body() + /// .into_raw_body().json::() /// .await?; /// # } /// ``` @@ -396,7 +396,7 @@ impl ContainerClient { /// /// By default, the created/replaced item is *not* returned in the HTTP response. /// If you want the created/replaced item to be returned, set the [`ItemOptions::enable_content_response_on_write`] option to `true`. - /// You can deserialize the returned item using [`Response::into_json_body`], like this: + /// You can deserialize the returned item using [`ResponseBody::json`](azure_core::http::response::ResponseBody::json), like this: /// /// ```rust,no_run /// use azure_data_cosmos::ItemOptions; @@ -422,7 +422,7 @@ impl ContainerClient { /// let updated_product = container_client /// .upsert_item("category1", p, Some(options)) /// .await? - /// .into_json_body::() + /// .into_raw_body().json::() /// .await?; /// Ok(()) /// # } @@ -477,18 +477,18 @@ impl ContainerClient { /// let item: Product = container_client /// .read_item("partition1", "item1", None) /// .await? - /// .into_json_body() + /// .into_body() /// .await?; /// println!("Read Item: {:#?}", item); /// # Ok(()) /// # } /// ``` - pub async fn read_item( + pub async fn read_item( &self, partition_key: impl Into, item_id: &str, options: Option>, - ) -> azure_core::Result { + ) -> azure_core::Result> { let options = options.unwrap_or_default(); let link = self.items_link.item(item_id); let url = self.pipeline.url(&link); @@ -562,7 +562,7 @@ impl ContainerClient { /// /// By default, the patched item is *not* returned in the HTTP response. /// If you want the patched item to be returned, set the [`ItemOptions::enable_content_response_on_write`] option to `true`. - /// You can deserialize the returned item using [`Response::into_json_body`], like this: + /// You can deserialize the returned item using [`ResponseBody::json`](azure_core::http::response::ResponseBody::json), like this: /// /// For example: /// @@ -586,7 +586,7 @@ impl ContainerClient { /// let patched_item = client /// .patch_item("partition1", "item1", patch, Some(options)) /// .await? - /// .into_json_body::() + /// .into_raw_body().json::() /// .await?; /// # Ok(()) /// # } diff --git a/sdk/cosmos/azure_data_cosmos/tests/cosmos_items.rs b/sdk/cosmos/azure_data_cosmos/tests/cosmos_items.rs index 1aebd8627c..9664e20c63 100644 --- a/sdk/cosmos/azure_data_cosmos/tests/cosmos_items.rs +++ b/sdk/cosmos/azure_data_cosmos/tests/cosmos_items.rs @@ -77,7 +77,7 @@ pub async fn item_create_read_replace_delete(context: TestContext) -> Result<(), let read_item: TestItem = container_client .read_item("Partition1", "Item1", None) .await? - .into_json_body() + .into_body() .await?; assert_eq!(item, read_item); @@ -105,7 +105,8 @@ pub async fn item_create_read_replace_delete(context: TestContext) -> Result<(), }), ) .await? - .into_json_body() + .into_raw_body() + .json() .await?; assert_eq!(item, updated_item); @@ -118,7 +119,7 @@ pub async fn item_create_read_replace_delete(context: TestContext) -> Result<(), // Try to read the item again, expecting a 404 let result = container_client - .read_item("Partition1", "Item1", None) + .read_item::("Partition1", "Item1", None) .await; match result { Ok(_) => return Err("expected a 404 error when reading the deleted item".into()), @@ -165,7 +166,8 @@ pub async fn item_create_content_response_on_write( }), ) .await? - .into_json_body() + .into_raw_body() + .json() .await?; assert_eq!(item, response_item); @@ -196,7 +198,7 @@ pub async fn item_read_system_properties(context: TestContext) -> Result<(), Box let read_item: serde_json::Value = container_client .read_item("Partition1", "Item1", None) .await? - .into_json_body() + .into_body() .await?; assert!( read_item.get("_rid").is_some(), @@ -233,7 +235,7 @@ pub async fn item_upsert_new(context: TestContext) -> Result<(), Box> let read_item: TestItem = container_client .read_item("Partition1", "Item1", None) .await? - .into_json_body() + .into_body() .await?; assert_eq!(item, read_item); @@ -273,7 +275,8 @@ pub async fn item_upsert_existing(context: TestContext) -> Result<(), Box Result<(), Box> { let patched_item: TestItem = container_client .read_item("Partition1", "Item1", None) .await? - .into_json_body() + .into_body() .await?; assert_eq!("Patched", patched_item.nested.nested_value); assert_eq!(52, patched_item.value); @@ -327,7 +330,8 @@ pub async fn item_patch(context: TestContext) -> Result<(), Box> { }), ) .await? - .into_json_body() + .into_raw_body() + .json() .await?; assert!(!response_item.bool_value); @@ -360,7 +364,7 @@ pub async fn item_null_partition_key(context: TestContext) -> Result<(), Box Result<(), Box((), "Item1", None) + .await; match result { Ok(_) => return Err("expected a 404 error when reading the deleted item".into()), Err(err) => { diff --git a/sdk/identity/azure_identity/src/credentials/client_certificate_credentials.rs b/sdk/identity/azure_identity/src/credentials/client_certificate_credentials.rs index ae2354cfd3..ccbb138b72 100644 --- a/sdk/identity/azure_identity/src/credentials/client_certificate_credentials.rs +++ b/sdk/identity/azure_identity/src/credentials/client_certificate_credentials.rs @@ -254,7 +254,7 @@ impl ClientCertificateCredential { return Err(http_response_from_body(rsp_status, &rsp_body).into_error()); } - let response: EntraIdTokenResponse = rsp.into_json_body().await?; + let response: EntraIdTokenResponse = rsp.into_raw_body().json().await?; Ok(AccessToken::new( response.access_token, OffsetDateTime::now_utc() + Duration::from_secs(response.expires_in), diff --git a/sdk/typespec/typespec_client_core/src/http/options/transport.rs b/sdk/typespec/typespec_client_core/src/http/options/transport.rs index 8d76e84af9..3a9b6a06c0 100644 --- a/sdk/typespec/typespec_client_core/src/http/options/transport.rs +++ b/sdk/typespec/typespec_client_core/src/http/options/transport.rs @@ -49,7 +49,7 @@ impl TransportOptions { I::Custom(s) => s.send(ctx, request, &[]).await, }; - raw_response.map(|r| r.into_typed()) + raw_response.map(|r| r.with_model_type()) } } diff --git a/sdk/typespec/typespec_client_core/src/http/pipeline.rs b/sdk/typespec/typespec_client_core/src/http/pipeline.rs index 4372d5eb25..21495b3e60 100644 --- a/sdk/typespec/typespec_client_core/src/http/pipeline.rs +++ b/sdk/typespec/typespec_client_core/src/http/pipeline.rs @@ -88,7 +88,18 @@ impl Pipeline { self.pipeline[0] .send(ctx, request, &self.pipeline[1..]) .await - .map(|r| r.into_typed()) + .map(|r| r.with_model_type()) + } + + pub async fn send_format( + &self, + ctx: &Context<'_>, + request: &mut Request, + ) -> crate::Result> { + self.pipeline[0] + .send(ctx, request, &self.pipeline[1..]) + .await + .map(|r| r.with_model_type()) } } diff --git a/sdk/typespec/typespec_client_core/src/http/response.rs b/sdk/typespec/typespec_client_core/src/http/response.rs index 1e1db742c1..6e51557e52 100644 --- a/sdk/typespec/typespec_client_core/src/http/response.rs +++ b/sdk/typespec/typespec_client_core/src/http/response.rs @@ -35,7 +35,7 @@ impl Response { /// Converts an "untyped" raw response into a typed response, using the specified format. /// /// This method is intended for use in service clients, to "set" the model type for a raw response receieved from the pipeline. - pub fn into_typed(self) -> Response { + pub fn with_model_type(self) -> Response { Response { status: self.status, headers: self.headers, @@ -88,6 +88,18 @@ impl Response { pub fn into_raw_body(self) -> ResponseBody { self.body } + + /// Changes the format of the response body to the specified format. + /// + /// This method is intended for use in service clients, to "set" the model type for a raw response receieved from the pipeline. + pub fn with_format(self) -> Response { + Response { + status: self.status, + headers: self.headers, + body: self.body, + phantom: PhantomData, + } + } } impl, F: Format> Response { diff --git a/sdk/typespec/typespec_macros/tests/compilation-tests.rs b/sdk/typespec/typespec_macros/tests/compilation-tests.rs deleted file mode 100644 index 11ab213f91..0000000000 --- a/sdk/typespec/typespec_macros/tests/compilation-tests.rs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -use std::{ - collections::HashMap, - path::{Path, PathBuf}, - process::Stdio, -}; - -use cargo_metadata::{diagnostic::DiagnosticLevel, Message}; -use serde::Serialize; - -#[derive(Serialize)] -struct MessageExpectation { - pub level: DiagnosticLevel, - pub code: Option, - pub message: Option, - pub spans: Vec, -} - -#[derive(Serialize)] -struct MessageSpan { - pub file_name: String, - pub line: usize, // We only check the line number of the span because other properties (like highlight span) can vary by compiler version. -} - -#[derive(Serialize)] -#[serde(transparent)] -struct FileResult { - pub messages: Vec, -} - -/// Finds relative paths to files within root, with 'path_prefix' tracking the relative directories descended -fn find_recursive(root: &Path, path_prefix: &Path, file_suffix: &str) -> Vec { - let mut vec = Vec::new(); - if !root.is_dir() { - return vec; - } - - for dirent in root.read_dir().expect("to be able to read the directory") { - let dirent = dirent.expect("to have a valid directory entry (dirent)"); - let file_type = dirent.file_type().expect("to have a valid file type"); - let file_name = dirent - .file_name() - .into_string() - .expect("to have a valid UTF-8 file name"); - let mut path = path_prefix.to_path_buf(); - path.push(&file_name); - if file_type.is_file() && file_name.ends_with(file_suffix) { - let file_name = format!("{}.rs", &file_name[..(file_name.len() - file_suffix.len())]); - path.set_file_name(file_name); - vec.push(path.to_str().expect("path is valid UTF-8").to_string()); - } else if file_type.is_dir() { - vec.append(&mut find_recursive(&dirent.path(), &path, file_suffix)); - } - } - - vec -} - -#[test] -pub fn compilation_tests() { - let test_root = { - let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - p.push("tests"); - p.push("data"); - p.push("compilation-tests"); - p - }; - let repo_root = { - let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); // [root]/sdk/typespec/typespec_macros - p.pop(); // [root]/sdk/typespec - p.pop(); // [root]/sdk - p.pop(); // [root] - p - }; - - let mut expected_files = find_recursive(&test_root, Path::new(""), ".expected.json"); - expected_files.sort(); - - // Probably save to assume cargo is on the path, but if that's not the case, tests will start failing and we'll figure it out. - let output = std::process::Command::new(env!("CARGO")) - .arg("build") - .arg("--locked") - .arg("--message-format") - .arg("json") - .current_dir(test_root.clone()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .expect("cargo to start running") - .wait_with_output() - .expect("the compilation to run to completion"); - assert!(!output.status.success(), "compilation should have failed"); - - // Collect output and error and write them - let stdout = String::from_utf8(output.stdout).expect("stdout should be valid UTF-8"); - let stderr = String::from_utf8(output.stderr).expect("stderr should be valid UTF-8"); - println!( - "==== Standard Output ====\n{}\n==== End Standard Output ====", - &stdout - ); - println!( - "==== Standard Error ====\n{}\n==== End Standard Error ====", - &stderr - ); - let messages = Message::parse_stream(stdout.as_bytes()); - let file_messages = messages - .filter_map(|m| match m.expect("failed to parse message") { - Message::CompilerMessage(m) => Some(m), - _ => None, - }) - // Group by primary_span's src path - .fold(HashMap::new(), |mut map, msg| { - let Some(primary_span) = msg.message.spans.iter().find(|s| s.is_primary) else { - // No primary span, don't add this to the map. - return map; - }; - - // Convert the spans - let spans: Vec = msg - .message - .spans - .iter() - .map(|span| { - let mut span_file_name = PathBuf::from(&span.file_name); - if span_file_name.is_relative() { - span_file_name = test_root.join(span_file_name) - } - assert!(span_file_name.is_absolute()); - - #[allow(clippy::expect_fun_call)] - let relative_span_path = span_file_name - .strip_prefix(&repo_root) - .expect(&format!( - "span path {} is not relative to test_root {:?}", - &span.file_name, &repo_root - )) - .to_path_buf(); - - MessageSpan { - file_name: relative_span_path - .to_str() - .expect("failed to convert span path to string") - .replace("\\", "/"), - line: span.line_start, - } - }) - .collect(); - - let expectation = MessageExpectation { - code: msg.message.code.clone().map(|c| c.code), - level: msg.message.level, - message: match msg.message.code { - // If there's a 'code', the message comes from rustc (not our macro). - // In that case, clear the 'rendered' and 'message' properties, they can be volatile from compiler version to compiler version - Some(_) => None, - None => Some(msg.message.message), - }, - spans, - }; - - map.entry(primary_span.file_name.clone()) - .or_insert_with(|| FileResult { - messages: Vec::new(), - }) - .messages - .push(expectation); - map - }); - let mut files_with_errors: Vec = file_messages.keys().cloned().collect(); - files_with_errors.sort(); - println!("Found errors in files:\n{:?}", files_with_errors); - println!("Expect errors in files:\n{:?}", expected_files); - assert_eq!(files_with_errors, expected_files); - - // Now, for each group, generate/validate baselines depending on the env var AZSDK_GENERATE_BASELINES - let generate_baselines = std::env::var("AZSDK_GENERATE_BASELINES") - .map(|b| b.as_str() == "1") - .unwrap_or(false); - - let mut errors = String::new(); - for (src_path, messages) in file_messages.iter() { - let baseline_path = { - let mut p = test_root.clone(); - p.push(src_path); - p.set_extension("expected.json"); - p - }; - - let actual_path = { - let mut p = test_root.clone(); - p.push(src_path); - p.set_extension("actual.json"); - p - }; - - let serialized = serde_json::to_string_pretty(&messages) - .expect("failed to serialize message") - .trim() - .to_string(); - - if generate_baselines { - std::fs::write(&baseline_path, serialized).expect("failed to write baseline"); - } else { - assert!(baseline_path.exists()); - - // Write the actual file - std::fs::write(&actual_path, serialized.clone()).expect("failed to write actual"); - - // Read the baseline file - let baseline = - String::from_utf8(std::fs::read(&baseline_path).expect("failed to read baseline")) - .expect("invalid baseline file") - .trim() - .to_string(); - if baseline != serialized { - let diff_command = format!("diff {:?} {:?}", baseline_path, actual_path); - errors.push_str(&format!( - "=== {} does not match baseline ===\nRun `{}` to compare.\n\nActual Payload:\n{}\n===\n", - src_path, diff_command, serialized - )); - } - } - } - - if !errors.is_empty() { - panic!("{}", errors); - } -} diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/.gitignore b/sdk/typespec/typespec_macros/tests/data/compilation-tests/.gitignore deleted file mode 100644 index 9da4a887b3..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!Cargo.lock diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/Cargo.toml b/sdk/typespec/typespec_macros/tests/data/compilation-tests/Cargo.toml deleted file mode 100644 index 6c84d7ed52..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[workspace] -# This package is INTENTIONALLY omitted from the workspace because it contains files that do not compile (as part of testing compilation error reporting) -# So we create a workspace node to tell cargo this is the root of a workspace - -[package] -name = "compilation_tests" -version = "0.1.0" -edition = "2021" -publish = false - -[dependencies] -litemap = "0.7.4" -openssl = "0.10.72" -serde = { version = "1.0", features = ["derive"] } -typespec_client_core = { path = "../../../../typespec_client_core", features = [ - "derive", -] } -zerofrom = "0.1.5" diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/.gitignore b/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/.gitignore deleted file mode 100644 index c70d9603b7..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Compilation test actual output, which should not be checked in. -*.actual.json diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/lib.rs b/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/lib.rs deleted file mode 100644 index ee2d47aec7..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -mod model; diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.expected.json b/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.expected.json deleted file mode 100644 index 661c918f0d..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.expected.json +++ /dev/null @@ -1,90 +0,0 @@ -[ - { - "level": "error", - "code": null, - "message": "invalid typespec attribute, expected attribute in form #[typespec(key = value)]", - "spans": [ - { - "file_name": "sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs", - "line": 8 - } - ] - }, - { - "level": "error", - "code": null, - "message": "expected string literal", - "spans": [ - { - "file_name": "sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs", - "line": 12 - } - ] - }, - { - "level": "error", - "code": null, - "message": "expected string literal", - "spans": [ - { - "file_name": "sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs", - "line": 16 - } - ] - }, - { - "level": "error", - "code": null, - "message": "expected string literal", - "spans": [ - { - "file_name": "sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs", - "line": 20 - } - ] - }, - { - "level": "error", - "code": null, - "message": "invalid module path: a b c", - "spans": [ - { - "file_name": "sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs", - "line": 24 - } - ] - }, - { - "level": "error", - "code": null, - "message": "expected string literal", - "spans": [ - { - "file_name": "sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs", - "line": 28 - } - ] - }, - { - "level": "error", - "code": null, - "message": "invalid typespec attribute, expected attribute in form #[typespec(key = value)]", - "spans": [ - { - "file_name": "sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs", - "line": 32 - } - ] - }, - { - "level": "error", - "code": null, - "message": "invalid typespec attribute, expected attribute in form #[typespec(key = value)]", - "spans": [ - { - "file_name": "sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs", - "line": 36 - } - ] - } -] diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs b/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs deleted file mode 100644 index fd8c6ba4d6..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/bad_attributes.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -use serde::Deserialize; -use typespec_client_core::http::Model; - -#[derive(Model, Deserialize)] -#[typespec(foobar)] -pub struct NotAValidAttribute {} - -#[derive(Model, Deserialize)] -#[typespec(crate = 42)] -pub struct NumericLiteralCrate {} - -#[derive(Model, Deserialize)] -#[typespec(crate = "a" + "b")] -pub struct BinExprCrate {} - -#[derive(Model, Deserialize)] -#[typespec(crate = @)] -pub struct UnexpectedTokenCrate {} - -#[derive(Model, Deserialize)] -#[typespec(crate = "a b c")] -pub struct InvalidPathOnCrate {} - -#[derive(Model, Deserialize)] -#[typespec(format = 42)] -pub struct NotAStringLiteralOnFormat {} - -#[derive(Model, Deserialize)] -#[typespec(format("json"))] -pub struct IncorrectAttributeFormat {} - -#[derive(Model, Deserialize)] -#[typespec = "whoop"] -pub struct NotAMetaListAttribute {} diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/mod.rs b/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/mod.rs deleted file mode 100644 index 33cc9ece30..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod bad_attributes; -mod not_derive_deserialize; -mod unknown_format; diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/not_derive_deserialize.expected.json b/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/not_derive_deserialize.expected.json deleted file mode 100644 index 40e0492973..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/not_derive_deserialize.expected.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "level": "error", - "code": "E0277", - "message": null, - "spans": [ - { - "file_name": "sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/not_derive_deserialize.rs", - "line": 6 - } - ] - } -] diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/not_derive_deserialize.rs b/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/not_derive_deserialize.rs deleted file mode 100644 index a9778a90ab..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/not_derive_deserialize.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -use typespec_client_core::http::Model; - -#[derive(Model)] -pub struct MyModel {} diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/unknown_format.expected.json b/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/unknown_format.expected.json deleted file mode 100644 index b40839b89b..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/unknown_format.expected.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "level": "error", - "code": null, - "message": "Unknown format 'foobar'", - "spans": [ - { - "file_name": "sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/unknown_format.rs", - "line": 8 - } - ] - } -] diff --git a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/unknown_format.rs b/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/unknown_format.rs deleted file mode 100644 index 554077fd26..0000000000 --- a/sdk/typespec/typespec_macros/tests/data/compilation-tests/src/model/unknown_format.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -use serde::Deserialize; -use typespec_client_core::http::Model; - -#[derive(Model, Deserialize)] -#[typespec(format = "foobar")] -pub struct MyModel {} From 9c0cd019903d1c1143434a9cd75eb577e1fb375e Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Mon, 5 May 2025 20:44:25 +0000 Subject: [PATCH 05/11] updates to generated crates --- .../src/generated/models/pub_models.rs | 72 +++++----- .../src/generated/models/pub_models.rs | 58 ++++---- .../src/generated/models/pub_models.rs | 22 +-- .../src/clients/blob_service_client.rs | 5 +- .../src/clients/block_blob_client.rs | 3 +- .../src/generated/clients/blob_client.rs | 1 + .../generated/clients/block_blob_client.rs | 5 +- .../src/generated/models/crate_models.rs | 6 +- .../src/generated/models/pub_models.rs | 126 ++++++------------ 9 files changed, 129 insertions(+), 169 deletions(-) diff --git a/sdk/keyvault/azure_security_keyvault_certificates/src/generated/models/pub_models.rs b/sdk/keyvault/azure_security_keyvault_certificates/src/generated/models/pub_models.rs index 3e435a9202..549b946477 100644 --- a/sdk/keyvault/azure_security_keyvault_certificates/src/generated/models/pub_models.rs +++ b/sdk/keyvault/azure_security_keyvault_certificates/src/generated/models/pub_models.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; use time::OffsetDateTime; /// Details of the organization administrator of the certificate issuer. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct AdministratorContact { /// Email address. #[serde(skip_serializing_if = "Option::is_none")] @@ -32,7 +32,7 @@ pub struct AdministratorContact { } /// The backup certificate result, containing the backup blob. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct BackupCertificateResult { /// The backup blob containing the backed up certificate. @@ -46,7 +46,7 @@ pub struct BackupCertificateResult { } /// A certificate bundle consists of a certificate (X509) plus its attributes. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct Certificate { /// The certificate attributes. @@ -103,7 +103,7 @@ pub struct Certificate { } /// The certificate management attributes. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct CertificateAttributes { /// Creation time in UTC. #[serde( @@ -155,7 +155,7 @@ pub struct CertificateAttributes { } /// A certificate operation is returned in case of asynchronous requests. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct CertificateOperation { /// Indicates if cancellation was requested on the certificate operation. @@ -206,7 +206,7 @@ pub struct CertificateOperation { } /// Management policy for a certificate. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct CertificatePolicy { /// The certificate attributes. #[serde(skip_serializing_if = "Option::is_none")] @@ -238,7 +238,7 @@ pub struct CertificatePolicy { } /// The certificate item containing certificate metadata. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct CertificateProperties { /// The certificate management attributes. @@ -265,7 +265,7 @@ pub struct CertificateProperties { } /// The contact information for the vault certificates. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct Contact { /// Email address. #[serde(skip_serializing_if = "Option::is_none")] @@ -281,7 +281,7 @@ pub struct Contact { } /// The contacts for the vault certificates. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct Contacts { /// The contact list for the vault certificates. #[serde(rename = "contacts", skip_serializing_if = "Option::is_none")] @@ -293,7 +293,7 @@ pub struct Contacts { } /// The certificate create parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct CreateCertificateParameters { /// The attributes of the certificate (optional). #[serde(rename = "attributes", skip_serializing_if = "Option::is_none")] @@ -315,7 +315,7 @@ pub struct CreateCertificateParameters { /// A Deleted Certificate consisting of its previous id, attributes and its tags, as well as information on when it will be /// purged. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct DeletedCertificate { /// The certificate attributes. @@ -394,7 +394,7 @@ pub struct DeletedCertificate { } /// The deleted certificate item containing metadata about the deleted certificate. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct DeletedCertificateProperties { /// The certificate management attributes. @@ -443,7 +443,7 @@ pub struct DeletedCertificateProperties { } /// The certificate import parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct ImportCertificateParameters { /// Base64 encoded representation of the certificate object to import. This certificate needs to contain the private key. #[serde(rename = "value", skip_serializing_if = "Option::is_none")] @@ -472,7 +472,7 @@ pub struct ImportCertificateParameters { } /// The issuer for Key Vault certificate. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct Issuer { /// Attributes of the issuer object. @@ -497,7 +497,7 @@ pub struct Issuer { } /// The attributes of an issuer managed by the Key Vault service. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct IssuerAttributes { /// Creation time in UTC. #[serde( @@ -521,7 +521,7 @@ pub struct IssuerAttributes { } /// The credentials to be used for the certificate issuer. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct IssuerCredentials { /// The user name/account name/account id. #[serde(skip_serializing_if = "Option::is_none")] @@ -533,7 +533,7 @@ pub struct IssuerCredentials { } /// Parameters for the issuer of the X509 component of a certificate. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct IssuerParameters { /// Indicates if the certificates generated under this policy should be published to certificate transparency logs. #[serde(rename = "cert_transparency", skip_serializing_if = "Option::is_none")] @@ -549,7 +549,7 @@ pub struct IssuerParameters { } /// The certificate issuer item containing certificate issuer metadata. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct IssuerProperties { /// Certificate Identifier. @@ -562,7 +562,7 @@ pub struct IssuerProperties { } /// Properties of the key pair backing a certificate. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct KeyProperties { /// Elliptic curve name. For valid values, see JsonWebKeyCurveName. #[serde(rename = "crv", skip_serializing_if = "Option::is_none")] @@ -586,7 +586,7 @@ pub struct KeyProperties { pub reuse_key: Option, } -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct KeyVaultErrorError { /// The error code. @@ -603,7 +603,7 @@ pub struct KeyVaultErrorError { } /// Action and its trigger that will be performed by Key Vault over the lifetime of a certificate. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct LifetimeAction { /// The action that will be executed. #[serde(skip_serializing_if = "Option::is_none")] @@ -615,7 +615,7 @@ pub struct LifetimeAction { } /// A condition to be satisfied for an action to be executed. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct LifetimeActionTrigger { /// Days before expiry to attempt renewal. Value should be between 1 and validity_in_months multiplied by 27. If validity_in_months /// is 36, then value should be between 1 and 972 (36 * 27). @@ -628,7 +628,7 @@ pub struct LifetimeActionTrigger { } /// The action that will be executed. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct LifetimeActionType { /// The type of the action. #[serde(skip_serializing_if = "Option::is_none")] @@ -636,7 +636,7 @@ pub struct LifetimeActionType { } /// The certificate list result. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct ListCertificatePropertiesResult { /// The URL to get the next set of certificates. @@ -649,7 +649,7 @@ pub struct ListCertificatePropertiesResult { } /// A list of certificates that have been deleted in this vault. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct ListDeletedCertificatePropertiesResult { /// The URL to get the next set of deleted certificates. @@ -663,7 +663,7 @@ pub struct ListDeletedCertificatePropertiesResult { } /// The certificate issuer list result. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct ListIssuerPropertiesResult { /// The URL to get the next set of certificate issuers. @@ -677,7 +677,7 @@ pub struct ListIssuerPropertiesResult { } /// The certificate merge parameters -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct MergeCertificateParameters { /// The attributes of the certificate (optional). #[serde(rename = "attributes", skip_serializing_if = "Option::is_none")] @@ -698,7 +698,7 @@ pub struct MergeCertificateParameters { } /// Details of the organization of the certificate issuer. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct OrganizationDetails { /// Details of the organization administrator. #[serde(rename = "admin_details", skip_serializing_if = "Option::is_none")] @@ -710,7 +710,7 @@ pub struct OrganizationDetails { } /// The certificate restore parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct RestoreCertificateParameters { /// The backup blob associated with a certificate bundle. #[serde( @@ -724,7 +724,7 @@ pub struct RestoreCertificateParameters { } /// Properties of the key backing a certificate. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct SecretProperties { /// The media type (MIME type). #[serde(rename = "contentType", skip_serializing_if = "Option::is_none")] @@ -732,7 +732,7 @@ pub struct SecretProperties { } /// The certificate issuer set parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct SetIssuerParameters { /// Attributes of the issuer object. #[serde(skip_serializing_if = "Option::is_none")] @@ -752,7 +752,7 @@ pub struct SetIssuerParameters { } /// The subject alternate names of a X509 object. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct SubjectAlternativeNames { /// Domain names. #[serde(skip_serializing_if = "Option::is_none")] @@ -768,7 +768,7 @@ pub struct SubjectAlternativeNames { } /// The certificate operation update parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct UpdateCertificateOperationParameter { /// Indicates if cancellation was requested on the certificate operation. #[serde(skip_serializing_if = "Option::is_none")] @@ -776,7 +776,7 @@ pub struct UpdateCertificateOperationParameter { } /// The certificate update parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct UpdateCertificatePropertiesParameters { /// The attributes of the certificate (optional). #[serde(rename = "attributes", skip_serializing_if = "Option::is_none")] @@ -792,7 +792,7 @@ pub struct UpdateCertificatePropertiesParameters { } /// The certificate issuer update parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct UpdateIssuerParameters { /// Attributes of the issuer object. #[serde(skip_serializing_if = "Option::is_none")] @@ -812,7 +812,7 @@ pub struct UpdateIssuerParameters { } /// Properties of the X509 component of a certificate. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct X509CertificateProperties { /// The enhanced key usage. #[serde(rename = "ekus", skip_serializing_if = "Option::is_none")] diff --git a/sdk/keyvault/azure_security_keyvault_keys/src/generated/models/pub_models.rs b/sdk/keyvault/azure_security_keyvault_keys/src/generated/models/pub_models.rs index 92c6b40574..233ba0d410 100644 --- a/sdk/keyvault/azure_security_keyvault_keys/src/generated/models/pub_models.rs +++ b/sdk/keyvault/azure_security_keyvault_keys/src/generated/models/pub_models.rs @@ -13,7 +13,7 @@ use std::collections::HashMap; use time::OffsetDateTime; /// The backup key result, containing the backup blob. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct BackupKeyResult { /// The backup blob containing the backed up key. @@ -27,7 +27,7 @@ pub struct BackupKeyResult { } /// The key create parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct CreateKeyParameters { /// Elliptic curve name. For valid values, see JsonWebKeyCurveName. #[serde(rename = "crv", skip_serializing_if = "Option::is_none")] @@ -63,7 +63,7 @@ pub struct CreateKeyParameters { } /// A DeletedKeyBundle consisting of a WebKey plus its Attributes and deletion info -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct DeletedKey { /// The key management attributes. @@ -110,7 +110,7 @@ pub struct DeletedKey { } /// The deleted key item containing the deleted key metadata and information about deletion. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct DeletedKeyProperties { /// The key management attributes. @@ -153,7 +153,7 @@ pub struct DeletedKeyProperties { } /// The get random bytes request object. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct GetRandomBytesParameters { /// The requested number of random bytes. #[serde(skip_serializing_if = "Option::is_none")] @@ -161,7 +161,7 @@ pub struct GetRandomBytesParameters { } /// The key import parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct ImportKeyParameters { /// Whether to import as a hardware key (HSM) or software key. #[serde(rename = "Hsm", skip_serializing_if = "Option::is_none")] @@ -185,7 +185,7 @@ pub struct ImportKeyParameters { } /// As of -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct JsonWebKey { /// Elliptic curve name. For valid values, see JsonWebKeyCurveName. #[serde(skip_serializing_if = "Option::is_none")] @@ -314,7 +314,7 @@ pub struct JsonWebKey { } /// A KeyBundle consisting of a WebKey plus its attributes. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct Key { /// The key management attributes. @@ -339,7 +339,7 @@ pub struct Key { } /// The key attestation information. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct KeyAttestation { /// A base64url-encoded string containing certificates in PEM format, used for attestation validation. #[serde( @@ -377,7 +377,7 @@ pub struct KeyAttestation { } /// The attributes of a key managed by the key vault service. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct KeyAttributes { /// The key or key version attestation information. #[serde(skip_serializing_if = "Option::is_none")] @@ -442,7 +442,7 @@ pub struct KeyAttributes { } /// The key operations parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct KeyOperationParameters { /// Additional data to authenticate but not encrypt/decrypt when using authenticated crypto algorithms. #[serde( @@ -488,7 +488,7 @@ pub struct KeyOperationParameters { } /// The key operation result. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct KeyOperationResult { /// Additional data to authenticate but not encrypt/decrypt when using authenticated crypto algorithms. @@ -536,7 +536,7 @@ pub struct KeyOperationResult { } /// The key item containing key metadata. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct KeyProperties { /// The key management attributes. @@ -557,7 +557,7 @@ pub struct KeyProperties { } /// The policy rules under which the key can be exported. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct KeyReleasePolicy { /// Content type and version of key release policy #[serde(rename = "contentType", skip_serializing_if = "Option::is_none")] @@ -580,7 +580,7 @@ pub struct KeyReleasePolicy { } /// The release result, containing the released key. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct KeyReleaseResult { /// A signed object containing the released key. @@ -589,7 +589,7 @@ pub struct KeyReleaseResult { } /// Management policy for a key. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct KeyRotationPolicy { /// The key rotation policy attributes. #[serde(skip_serializing_if = "Option::is_none")] @@ -607,7 +607,7 @@ pub struct KeyRotationPolicy { } /// The key rotation policy attributes. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct KeyRotationPolicyAttributes { /// The key rotation policy created time in UTC. #[serde( @@ -632,7 +632,7 @@ pub struct KeyRotationPolicyAttributes { } /// The key verify result. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct KeyVerifyResult { /// True if the signature is verified, otherwise false. @@ -641,7 +641,7 @@ pub struct KeyVerifyResult { } /// Action and its trigger that will be performed by Key Vault over the lifetime of a key. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct LifetimeAction { /// The action that will be executed. #[serde(skip_serializing_if = "Option::is_none")] @@ -653,7 +653,7 @@ pub struct LifetimeAction { } /// A condition to be satisfied for an action to be executed. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct LifetimeActionTrigger { /// Time after creation to attempt to rotate. It only applies to rotate. It will be in ISO 8601 duration format. Example: /// 90 days : "P90D" @@ -666,7 +666,7 @@ pub struct LifetimeActionTrigger { } /// The action that will be executed. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct LifetimeActionType { /// The type of the action. The value should be compared case-insensitively. #[serde(rename = "type", skip_serializing_if = "Option::is_none")] @@ -674,7 +674,7 @@ pub struct LifetimeActionType { } /// A list of keys that have been deleted in this vault. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct ListDeletedKeyPropertiesResult { /// The URL to get the next set of deleted keys. @@ -687,7 +687,7 @@ pub struct ListDeletedKeyPropertiesResult { } /// The key list result. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct ListKeyPropertiesResult { /// The URL to get the next set of keys. @@ -700,7 +700,7 @@ pub struct ListKeyPropertiesResult { } /// The get random bytes response object containing the bytes. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct RandomBytes { /// The bytes encoded as a base64url string. @@ -714,7 +714,7 @@ pub struct RandomBytes { } /// The release key parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct ReleaseParameters { /// The encryption algorithm to use to protected the exported key material #[serde(rename = "enc", skip_serializing_if = "Option::is_none")] @@ -730,7 +730,7 @@ pub struct ReleaseParameters { } /// The key restore parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct RestoreKeyParameters { /// The backup blob associated with a key bundle. #[serde( @@ -744,7 +744,7 @@ pub struct RestoreKeyParameters { } /// The key operations parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct SignParameters { /// The signing/verification algorithm identifier. For more information on possible algorithm types, see JsonWebKeySignatureAlgorithm. #[serde(rename = "alg", skip_serializing_if = "Option::is_none")] @@ -761,7 +761,7 @@ pub struct SignParameters { } /// The key update parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct UpdateKeyPropertiesParameters { /// The attributes of a key managed by the key vault service. #[serde(rename = "attributes", skip_serializing_if = "Option::is_none")] @@ -781,7 +781,7 @@ pub struct UpdateKeyPropertiesParameters { } /// The key verify parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct VerifyParameters { /// The signing/verification algorithm. For more information on possible algorithm types, see JsonWebKeySignatureAlgorithm. #[serde(rename = "alg", skip_serializing_if = "Option::is_none")] diff --git a/sdk/keyvault/azure_security_keyvault_secrets/src/generated/models/pub_models.rs b/sdk/keyvault/azure_security_keyvault_secrets/src/generated/models/pub_models.rs index e18192af63..814d28c9a8 100644 --- a/sdk/keyvault/azure_security_keyvault_secrets/src/generated/models/pub_models.rs +++ b/sdk/keyvault/azure_security_keyvault_secrets/src/generated/models/pub_models.rs @@ -10,7 +10,7 @@ use std::collections::HashMap; use time::OffsetDateTime; /// The backup secret result, containing the backup blob. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct BackupSecretResult { /// The backup blob containing the backed up secret. @@ -24,7 +24,7 @@ pub struct BackupSecretResult { } /// A Deleted Secret consisting of its previous id, attributes and its tags, as well as information on when it will be purged. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct DeletedSecret { /// The secret management attributes. @@ -80,7 +80,7 @@ pub struct DeletedSecret { } /// The deleted secret item containing metadata about the deleted secret. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct DeletedSecretProperties { /// The secret management attributes. @@ -127,7 +127,7 @@ pub struct DeletedSecretProperties { } /// The deleted secret list result -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct ListDeletedSecretPropertiesResult { /// The URL to get the next set of deleted secrets. @@ -141,7 +141,7 @@ pub struct ListDeletedSecretPropertiesResult { } /// The secret list result. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct ListSecretPropertiesResult { /// The URL to get the next set of secrets. @@ -154,7 +154,7 @@ pub struct ListSecretPropertiesResult { } /// The secret restore parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct RestoreSecretParameters { /// The backup blob associated with a secret bundle. #[serde( @@ -168,7 +168,7 @@ pub struct RestoreSecretParameters { } /// A secret consisting of a value, id and its attributes. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct Secret { /// The secret management attributes. @@ -202,7 +202,7 @@ pub struct Secret { } /// The secret management attributes. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct SecretAttributes { /// Creation time in UTC. #[serde( @@ -254,7 +254,7 @@ pub struct SecretAttributes { } /// The secret item containing secret metadata. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] pub struct SecretProperties { /// The secret management attributes. @@ -279,7 +279,7 @@ pub struct SecretProperties { } /// The secret set parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct SetSecretParameters { /// Type of the secret value such as a password. #[serde(rename = "contentType", skip_serializing_if = "Option::is_none")] @@ -299,7 +299,7 @@ pub struct SetSecretParameters { } /// The secret update parameters. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct UpdateSecretPropertiesParameters { /// Type of the secret value such as a password. #[serde(rename = "contentType", skip_serializing_if = "Option::is_none")] diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_service_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_service_client.rs index bfb1d9a345..a170bd56c7 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_service_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_service_client.rs @@ -15,6 +15,7 @@ use azure_core::{ Result, }; use std::sync::Arc; +use typespec_client_core::http::XmlFormat; /// A client to interact with an Azure storage account. pub struct BlobServiceClient { @@ -85,7 +86,7 @@ impl BlobServiceClient { pub async fn get_properties( &self, options: Option>, - ) -> Result> { - self.client.get_properties(options).await + ) -> Result> { + Ok(self.client.get_properties(options).await?.with_format()) } } diff --git a/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs index cd58b28848..276f13115b 100644 --- a/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs @@ -25,6 +25,7 @@ use azure_core::{ Bytes, Result, }; use std::sync::Arc; +use typespec_client_core::http::XmlFormat; /// A client to interact with a specific Azure storage Block blob, although that blob may not yet exist. pub struct BlockBlobClient { @@ -139,7 +140,7 @@ impl BlockBlobClient { &self, list_type: BlockListType, options: Option>, - ) -> Result> { + ) -> Result> { self.client.get_block_list(list_type, options).await } } diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs index a2790d6fe3..308d9a7ea5 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs @@ -37,6 +37,7 @@ use azure_core::{ Result, }; use std::sync::Arc; +use typespec_client_core::http::XmlFormat; pub struct BlobClient { pub(crate) blob_name: String, diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs index 1099b1e3c7..83407cc5d9 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs @@ -24,6 +24,7 @@ use azure_core::{ Bytes, Result, }; use std::sync::Arc; +use typespec_client_core::http::XmlFormat; pub struct BlockBlobClient { pub(crate) blob_name: String, @@ -229,7 +230,7 @@ impl BlockBlobClient { &self, list_type: BlockListType, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -260,7 +261,7 @@ impl BlockBlobClient { request.insert_header("x-ms-lease-id", lease_id); } request.insert_header("x-ms-version", &self.version); - self.pipeline.send(&ctx, &mut request).await + self.pipeline.send_format(&ctx, &mut request).await } /// The Put Blob from URL operation creates a new Block Blob where the contents of the blob are read from a given URL. This diff --git a/sdk/storage/azure_storage_blob/src/generated/models/crate_models.rs b/sdk/storage/azure_storage_blob/src/generated/models/crate_models.rs index f2638eeada..e314105f90 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/crate_models.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/crate_models.rs @@ -9,8 +9,7 @@ use super::{ use azure_core::{fmt::SafeDebug, http::RequestContent, xml::to_xml, Result}; use serde::{Deserialize, Serialize}; -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub(crate) struct GetUserDelegationKeyRequest { /// The date-time the key expires. #[serde(rename = "Expiry")] @@ -21,8 +20,7 @@ pub(crate) struct GetUserDelegationKeyRequest { pub(crate) start: String, } -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub(crate) struct SetPropertiesRequest { /// The CORS properties. #[serde( diff --git a/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs b/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs index 4a4403d42d..45cc06ae11 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs @@ -20,8 +20,7 @@ use std::collections::HashMap; use time::OffsetDateTime; /// Represents an access policy. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct AccessPolicy { /// The date-time the policy expires. #[serde( @@ -63,8 +62,7 @@ pub struct AppendBlobClientCreateResult; pub struct AppendBlobClientSealResult; /// Represents the Apache Arrow configuration. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct ArrowConfiguration { /// The Apache Arrow schema #[serde( @@ -78,9 +76,8 @@ pub struct ArrowConfiguration { } /// Represents an Apache Arrow field. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[serde(rename = "Field")] -#[typespec(format = "xml")] pub struct ArrowField { /// The arrow field name. #[serde(rename = "Name", skip_serializing_if = "Option::is_none")] @@ -212,10 +209,9 @@ pub struct BlobContainerClientRestoreResult; pub struct BlobContainerClientSetAccessPolicyResult; /// The blob flat list segment. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "Blobs")] -#[typespec(format = "xml")] pub struct BlobFlatListSegment { /// The blob items. #[serde( @@ -229,10 +225,9 @@ pub struct BlobFlatListSegment { } /// Represents an array of blobs. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "Blobs")] -#[typespec(format = "xml")] pub struct BlobHierarchyListSegment { /// The blob items #[serde( @@ -256,10 +251,9 @@ pub struct BlobHierarchyListSegment { } /// An Azure Storage Blob -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "Blob")] -#[typespec(format = "xml")] pub struct BlobItemInternal { /// The tags of the blob. #[serde(rename = "BlobTags", skip_serializing_if = "Option::is_none")] @@ -306,9 +300,8 @@ pub struct BlobItemInternal { } /// The blob metadata. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct BlobMetadata { /// Whether the blob metadata is encrypted. #[serde(rename = "@Encrypted", skip_serializing_if = "Option::is_none")] @@ -316,9 +309,8 @@ pub struct BlobMetadata { } /// Represents a blob name. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct BlobName { /// The blob name. #[serde(rename = "$text", skip_serializing_if = "Option::is_none")] @@ -330,9 +322,8 @@ pub struct BlobName { } /// Represents a blob prefix. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct BlobPrefix { /// The blob name. #[serde(rename = "Name", skip_serializing_if = "Option::is_none")] @@ -340,10 +331,9 @@ pub struct BlobPrefix { } /// The properties of a blob. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "Properties")] -#[typespec(format = "xml")] pub struct BlobPropertiesInternal { /// The access tier of the blob. #[serde(rename = "AccessTier", skip_serializing_if = "Option::is_none")] @@ -578,9 +568,8 @@ pub struct BlobPropertiesInternal { pub struct BlobServiceClientGetAccountInfoResult; /// The blob tags. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[serde(rename = "Tag")] -#[typespec(format = "xml")] pub struct BlobTag { /// The key of the tag. #[serde(rename = "Key", skip_serializing_if = "Option::is_none")] @@ -592,9 +581,8 @@ pub struct BlobTag { } /// Represents blob tags. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[serde(rename = "Tags")] -#[typespec(format = "xml")] pub struct BlobTags { /// Represents the blob tags. #[serde( @@ -608,9 +596,8 @@ pub struct BlobTags { } /// Represents a single block in a block blob. It describes the block's ID and size. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct Block { /// The base64 encoded block ID. #[serde( @@ -652,9 +639,8 @@ pub struct BlockBlobClientStageBlockResult; pub struct BlockBlobClientUploadResult; /// Contains the committed and uncommitted blocks in a block blob. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct BlockList { /// The list of committed blocks. #[serde( @@ -678,9 +664,8 @@ pub struct BlockList { } /// The Block lookup list. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[serde(rename = "BlockList")] -#[typespec(format = "xml")] pub struct BlockLookupList { /// The committed blocks #[serde( @@ -711,9 +696,8 @@ pub struct BlockLookupList { } /// The clear range. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct ClearRange { /// The end of the byte range. #[serde(rename = "End", skip_serializing_if = "Option::is_none")] @@ -725,10 +709,9 @@ pub struct ClearRange { } /// An Azure Storage container. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "Container")] -#[typespec(format = "xml")] pub struct ContainerItem { /// Whether the container is deleted. #[serde(rename = "Deleted", skip_serializing_if = "Option::is_none")] @@ -752,9 +735,8 @@ pub struct ContainerItem { } /// The properties of a container. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct ContainerProperties { /// The default encryption scope of the container. #[serde( @@ -837,8 +819,7 @@ pub struct ContainerProperties { /// CORS is an HTTP feature that enables a web application running under one domain to access resources in another domain. /// Web browsers implement a security restriction known as same-origin policy that prevents a web page from calling APIs in /// a different domain; CORS provides a secure way to allow one domain (the origin domain) to call APIs in another domain -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct CorsRule { /// The allowed headers. #[serde(rename = "AllowedHeaders", skip_serializing_if = "Option::is_none")] @@ -862,8 +843,7 @@ pub struct CorsRule { } /// Represents the delimited text configuration. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct DelimitedTextConfiguration { /// The string used to separate columns. #[serde(rename = "ColumnSeparator", skip_serializing_if = "Option::is_none")] @@ -887,10 +867,9 @@ pub struct DelimitedTextConfiguration { } /// The filter blob item. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "Blob")] -#[typespec(format = "xml")] pub struct FilterBlobItem { /// The properties of the blob. #[serde(rename = "ContainerName", skip_serializing_if = "Option::is_none")] @@ -914,10 +893,9 @@ pub struct FilterBlobItem { } /// The result of a Filter Blobs API call -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "EnumerationResults")] -#[typespec(format = "xml")] pub struct FilterBlobSegment { /// The blob segment. #[serde( @@ -943,9 +921,8 @@ pub struct FilterBlobSegment { } /// Geo-Replication information for the Secondary Storage Service -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct GeoReplication { /// A GMT date/time value, to the second. All primary writes preceding this value are guaranteed to be available for read /// operations at the secondary. Primary writes after this point in time may or may not be available for reads. @@ -963,8 +940,7 @@ pub struct GeoReplication { } /// Represents the JSON text configuration. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct JsonTextConfiguration { /// The string used to separate records. #[serde(rename = "RecordSeparator", skip_serializing_if = "Option::is_none")] @@ -972,10 +948,9 @@ pub struct JsonTextConfiguration { } /// An enumeration of blobs. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "EnumerationResults")] -#[typespec(format = "xml")] pub struct ListBlobsFlatSegmentResponse { /// The container name. #[serde(rename = "@ContainerName", skip_serializing_if = "Option::is_none")] @@ -1007,10 +982,9 @@ pub struct ListBlobsFlatSegmentResponse { } /// An enumeration of blobs -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "EnumerationResults")] -#[typespec(format = "xml")] pub struct ListBlobsHierarchySegmentResponse { /// The container name. #[serde(rename = "@ContainerName", skip_serializing_if = "Option::is_none")] @@ -1046,10 +1020,9 @@ pub struct ListBlobsHierarchySegmentResponse { } /// The list container segment response -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "EnumerationResults")] -#[typespec(format = "xml")] pub struct ListContainersSegmentResponse { /// The container segment. #[serde( @@ -1083,8 +1056,7 @@ pub struct ListContainersSegmentResponse { } /// Azure Analytics Logging settings. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct Logging { /// Whether delete operation is logged. #[serde(rename = "Delete", skip_serializing_if = "Option::is_none")] @@ -1108,8 +1080,7 @@ pub struct Logging { } /// The metrics properties. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct Metrics { /// Whether it is enabled. #[serde(rename = "Enabled", skip_serializing_if = "Option::is_none")] @@ -1129,10 +1100,9 @@ pub struct Metrics { } /// The object replication metadata. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] #[serde(rename = "OrMetadata")] -#[typespec(format = "xml")] pub struct ObjectReplicationMetadata {} /// Contains results for `PageBlobClient::clear_pages()` @@ -1164,9 +1134,8 @@ pub struct PageBlobClientUploadPagesFromUrlResult; pub struct PageBlobClientUploadPagesResult; /// Represents a page list. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct PageList { /// The clear ranges. #[serde( @@ -1194,9 +1163,8 @@ pub struct PageList { } /// The page range. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct PageRange { /// The end of the byte range. #[serde(rename = "End", skip_serializing_if = "Option::is_none")] @@ -1208,13 +1176,11 @@ pub struct PageRange { } /// Represents the Parquet configuration. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct ParquetConfiguration {} /// The query format settings. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct QueryFormat { /// The Apache Arrow configuration. #[serde(rename = "ArrowConfiguration", skip_serializing_if = "Option::is_none")] @@ -1247,8 +1213,7 @@ pub struct QueryFormat { } /// Groups the set of query request settings. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct QueryRequest { /// The query expression in SQL. The maximum size of the query expression is 256KiB. #[serde(rename = "Expression", skip_serializing_if = "Option::is_none")] @@ -1271,8 +1236,7 @@ pub struct QueryRequest { } /// The query serialization settings. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct QuerySerialization { /// The query format. #[serde(rename = "Format", skip_serializing_if = "Option::is_none")] @@ -1280,8 +1244,7 @@ pub struct QuerySerialization { } /// The retention policy. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct RetentionPolicy { /// Whether to allow permanent delete. #[serde( @@ -1300,9 +1263,8 @@ pub struct RetentionPolicy { } /// The signed identifier. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[serde(rename = "SignedIdentifier")] -#[typespec(format = "xml")] pub struct SignedIdentifier { /// The access policy for the signed identifier. #[serde(rename = "AccessPolicy", skip_serializing_if = "Option::is_none")] @@ -1314,8 +1276,7 @@ pub struct SignedIdentifier { } /// The properties that enable an account to host a static website -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] -#[typespec(format = "xml")] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct StaticWebsite { /// Absolute path of the default index page #[serde( @@ -1341,9 +1302,8 @@ pub struct StaticWebsite { } /// The service properties. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct StorageServiceProperties { /// The CORS properties. #[serde( @@ -1387,9 +1347,8 @@ pub struct StorageServiceProperties { } /// Stats for the storage service. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct StorageServiceStats { /// The geo replication stats. #[serde(rename = "GeoReplication", skip_serializing_if = "Option::is_none")] @@ -1397,9 +1356,8 @@ pub struct StorageServiceStats { } /// A user delegation key. -#[derive(Clone, Default, Deserialize, SafeDebug, Serialize, azure_core::http::Model)] +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] -#[typespec(format = "xml")] pub struct UserDelegationKey { /// The date-time the key expires. #[serde(rename = "SignedExpiry", skip_serializing_if = "Option::is_none")] From 81f41d763b382f7553c1a226c6579b663850fbbf Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Mon, 5 May 2025 21:00:54 +0000 Subject: [PATCH 06/11] make send_format more clearly a short-cut method --- sdk/typespec/typespec_client_core/src/http/pipeline.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sdk/typespec/typespec_client_core/src/http/pipeline.rs b/sdk/typespec/typespec_client_core/src/http/pipeline.rs index 21495b3e60..f501404391 100644 --- a/sdk/typespec/typespec_client_core/src/http/pipeline.rs +++ b/sdk/typespec/typespec_client_core/src/http/pipeline.rs @@ -96,10 +96,7 @@ impl Pipeline { ctx: &Context<'_>, request: &mut Request, ) -> crate::Result> { - self.pipeline[0] - .send(ctx, request, &self.pipeline[1..]) - .await - .map(|r| r.with_model_type()) + self.send(ctx, request).await.map(|r| r.with_format()) } } From d8b61193d3de299c4ed873dc8ab21551411e8d98 Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Mon, 5 May 2025 22:04:09 +0000 Subject: [PATCH 07/11] fix async_trait on wasm32 --- sdk/typespec/typespec_client_core/src/http/format.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sdk/typespec/typespec_client_core/src/http/format.rs b/sdk/typespec/typespec_client_core/src/http/format.rs index 5dc8279e98..f85be237d9 100644 --- a/sdk/typespec/typespec_client_core/src/http/format.rs +++ b/sdk/typespec/typespec_client_core/src/http/format.rs @@ -18,13 +18,15 @@ pub trait Format {} /// /// This trait defines the `deserialize_with` method, which takes a [`ResponseBody`] and returns the deserialized value. /// The `F` type parameter allows for different implementations of the `deserialize_with` method based on the specific [`Format`] marker type used. -#[async_trait::async_trait] +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] pub trait DeserializeWith: Sized { async fn deserialize_with(body: ResponseBody) -> typespec::Result; } /// Implements [`DeserializeWith`] for [`ResponseBody`], by simply returning the body stream as is. -#[async_trait::async_trait] +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl DeserializeWith for ResponseBody { async fn deserialize_with(body: ResponseBody) -> typespec::Result { Ok(body) @@ -33,7 +35,8 @@ impl DeserializeWith for ResponseBody { /// Implements [`DeserializeWith`] for an arbitrary type `D` /// that implements [`serde::de::DeserializeOwned`] by deserializing the response body to the specified type using [`serde_json`]. -#[async_trait::async_trait] +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl DeserializeWith for D { async fn deserialize_with(body: ResponseBody) -> typespec::Result { body.json().await @@ -57,7 +60,8 @@ pub struct XmlFormat; impl Format for XmlFormat {} #[cfg(feature = "xml")] -#[async_trait::async_trait] +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl DeserializeWith for D { async fn deserialize_with(body: ResponseBody) -> typespec::Result { body.xml().await From b81c09a27359f97c72d7f94873f238a3973c7a85 Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Mon, 5 May 2025 22:04:51 +0000 Subject: [PATCH 08/11] fix tyop --- sdk/typespec/typespec_client_core/src/http/response.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/typespec/typespec_client_core/src/http/response.rs b/sdk/typespec/typespec_client_core/src/http/response.rs index 6e51557e52..854d4aeea2 100644 --- a/sdk/typespec/typespec_client_core/src/http/response.rs +++ b/sdk/typespec/typespec_client_core/src/http/response.rs @@ -34,7 +34,7 @@ pub struct Response { impl Response { /// Converts an "untyped" raw response into a typed response, using the specified format. /// - /// This method is intended for use in service clients, to "set" the model type for a raw response receieved from the pipeline. + /// This method is intended for use in service clients, to "set" the model type for a raw response received from the pipeline. pub fn with_model_type(self) -> Response { Response { status: self.status, @@ -91,7 +91,7 @@ impl Response { /// Changes the format of the response body to the specified format. /// - /// This method is intended for use in service clients, to "set" the model type for a raw response receieved from the pipeline. + /// This method is intended for use in service clients, to "set" the model type for a raw response received from the pipeline. pub fn with_format(self) -> Response { Response { status: self.status, From a22a9f1188a2ad2e7d7ed96d1e615642404ee850 Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Thu, 8 May 2025 17:41:49 +0000 Subject: [PATCH 09/11] initial pr feedback --- sdk/typespec/typespec_client_core/src/http/format.rs | 5 ++++- sdk/typespec/typespec_client_core/src/http/response.rs | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/sdk/typespec/typespec_client_core/src/http/format.rs b/sdk/typespec/typespec_client_core/src/http/format.rs index f85be237d9..3c82402555 100644 --- a/sdk/typespec/typespec_client_core/src/http/format.rs +++ b/sdk/typespec/typespec_client_core/src/http/format.rs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + use serde::de::DeserializeOwned; use crate::http::response::ResponseBody; @@ -27,7 +30,7 @@ pub trait DeserializeWith: Sized { /// Implements [`DeserializeWith`] for [`ResponseBody`], by simply returning the body stream as is. #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl DeserializeWith for ResponseBody { +impl DeserializeWith for ResponseBody { async fn deserialize_with(body: ResponseBody) -> typespec::Result { Ok(body) } diff --git a/sdk/typespec/typespec_client_core/src/http/response.rs b/sdk/typespec/typespec_client_core/src/http/response.rs index 854d4aeea2..3edbf8b5ca 100644 --- a/sdk/typespec/typespec_client_core/src/http/response.rs +++ b/sdk/typespec/typespec_client_core/src/http/response.rs @@ -28,7 +28,7 @@ pub struct Response { status: StatusCode, headers: Headers, body: ResponseBody, - phantom: PhantomData<(T, F)>, + _phantom: PhantomData<(T, F)>, } impl Response { @@ -40,7 +40,7 @@ impl Response { status: self.status, headers: self.headers, body: self.body, - phantom: PhantomData, + _phantom: PhantomData, } } } @@ -52,7 +52,7 @@ impl Response { status, headers, body: ResponseBody::new(stream), - phantom: PhantomData, + _phantom: PhantomData, } } @@ -62,7 +62,7 @@ impl Response { status, headers, body: ResponseBody::from_bytes(bytes), - phantom: PhantomData, + _phantom: PhantomData, } } @@ -97,7 +97,7 @@ impl Response { status: self.status, headers: self.headers, body: self.body, - phantom: PhantomData, + _phantom: PhantomData, } } } From 65b9317bbd1363ff2c0a862ad844668f5972f575 Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Thu, 8 May 2025 17:43:04 +0000 Subject: [PATCH 10/11] rename DefaultFormat to JsonFormat --- sdk/typespec/typespec_client_core/src/http/format.rs | 6 +++--- sdk/typespec/typespec_client_core/src/http/pipeline.rs | 4 ++-- sdk/typespec/typespec_client_core/src/http/response.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sdk/typespec/typespec_client_core/src/http/format.rs b/sdk/typespec/typespec_client_core/src/http/format.rs index 3c82402555..430e39b934 100644 --- a/sdk/typespec/typespec_client_core/src/http/format.rs +++ b/sdk/typespec/typespec_client_core/src/http/format.rs @@ -40,7 +40,7 @@ impl DeserializeWith for ResponseBody { /// that implements [`serde::de::DeserializeOwned`] by deserializing the response body to the specified type using [`serde_json`]. #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl DeserializeWith for D { +impl DeserializeWith for D { async fn deserialize_with(body: ResponseBody) -> typespec::Result { body.json().await } @@ -51,9 +51,9 @@ impl DeserializeWith for D { /// This format supports deserializing response bodies to: /// * [`ResponseBody`] - The raw response body, without any deserialization. /// * Any value implementing [`serde::de::DeserializeOwned`] - Deserializes the response body to the specified type using JSON deserialization. -pub struct DefaultFormat; +pub struct JsonFormat; -impl Format for DefaultFormat {} +impl Format for JsonFormat {} /// A [`Format`] that deserializes response bodies using XML. #[cfg(feature = "xml")] diff --git a/sdk/typespec/typespec_client_core/src/http/pipeline.rs b/sdk/typespec/typespec_client_core/src/http/pipeline.rs index f501404391..921d5fabb0 100644 --- a/sdk/typespec/typespec_client_core/src/http/pipeline.rs +++ b/sdk/typespec/typespec_client_core/src/http/pipeline.rs @@ -7,7 +7,7 @@ use crate::http::{ }; use std::sync::Arc; -use super::DefaultFormat; +use super::JsonFormat; /// Execution pipeline. /// @@ -84,7 +84,7 @@ impl Pipeline { &self, ctx: &Context<'_>, request: &mut Request, - ) -> crate::Result> { + ) -> crate::Result> { self.pipeline[0] .send(ctx, request, &self.pipeline[1..]) .await diff --git a/sdk/typespec/typespec_client_core/src/http/response.rs b/sdk/typespec/typespec_client_core/src/http/response.rs index 3edbf8b5ca..1b88a17644 100644 --- a/sdk/typespec/typespec_client_core/src/http/response.rs +++ b/sdk/typespec/typespec_client_core/src/http/response.rs @@ -3,7 +3,7 @@ //! HTTP responses. -use crate::http::{headers::Headers, DefaultFormat, DeserializeWith, Format, StatusCode}; +use crate::http::{headers::Headers, DeserializeWith, Format, JsonFormat, StatusCode}; use bytes::Bytes; use futures::{Stream, StreamExt}; use serde::de::DeserializeOwned; @@ -24,7 +24,7 @@ pub type PinnedStream = Pin>>>; /// Given a `Response`, a user can deserialize the body into the intended body type `T` by calling [`Response::into_body`]. /// However, because the type `T` is just a marker type, the user can also deserialize the body into a different type by calling [`Response::into_json_body`] or [`Response::into_xml_body`], /// or access the raw body using [`Response::into_raw_body`]. -pub struct Response { +pub struct Response { status: StatusCode, headers: Headers, body: ResponseBody, From c29e3f7f98fe09b7fded555a068472eebc3fb87a Mon Sep 17 00:00:00 2001 From: Ashley Stanton-Nurse Date: Thu, 8 May 2025 21:21:08 +0000 Subject: [PATCH 11/11] paramerize pipeline on format --- sdk/core/azure_core/src/http/mod.rs | 6 ++- sdk/core/azure_core/src/http/pipeline.rs | 13 +++-- .../src/clients/blob_client.rs | 15 +++--- .../src/clients/blob_container_client.rs | 9 ++-- .../src/clients/block_blob_client.rs | 4 +- .../generated/clients/append_blob_client.rs | 11 +++-- .../src/generated/clients/blob_client.rs | 48 +++++++++---------- .../clients/blob_container_client.rs | 37 +++++++------- .../generated/clients/blob_service_client.rs | 17 +++---- .../generated/clients/block_blob_client.rs | 16 +++---- .../src/generated/clients/page_blob_client.rs | 21 ++++---- .../src/generated/models/header_traits.rs | 20 ++++---- .../azure_storage_blob_test/src/lib.rs | 4 +- .../typespec_client_core/src/http/format.rs | 4 +- .../typespec_client_core/src/http/pipeline.rs | 29 ++++++----- 15 files changed, 136 insertions(+), 118 deletions(-) diff --git a/sdk/core/azure_core/src/http/mod.rs b/sdk/core/azure_core/src/http/mod.rs index cbf05ed773..866ea62e2b 100644 --- a/sdk/core/azure_core/src/http/mod.rs +++ b/sdk/core/azure_core/src/http/mod.rs @@ -21,5 +21,9 @@ pub use response::Response; pub use typespec_client_core::http::response; pub use typespec_client_core::http::{ - new_http_client, AppendToUrlQuery, Context, HttpClient, Method, StatusCode, Url, + new_http_client, AppendToUrlQuery, Context, Format, HttpClient, JsonFormat, Method, StatusCode, + Url, }; + +#[cfg(feature = "xml")] +pub use typespec_client_core::http::XmlFormat; diff --git a/sdk/core/azure_core/src/http/pipeline.rs b/sdk/core/azure_core/src/http/pipeline.rs index c6cce10dfb..2b3d14a432 100644 --- a/sdk/core/azure_core/src/http/pipeline.rs +++ b/sdk/core/azure_core/src/http/pipeline.rs @@ -8,7 +8,7 @@ use std::{ ops::Deref, sync::Arc, }; -use typespec_client_core::http::{self, policies::Policy}; +use typespec_client_core::http::{self, policies::Policy, Format, JsonFormat}; /// Execution pipeline. /// @@ -34,14 +34,17 @@ use typespec_client_core::http::{self, policies::Policy}; /// cannot be enforced by code). All policies except Transport policy can assume there is another following policy (so /// `self.pipeline[0]` is always valid). #[derive(Debug, Clone)] -pub struct Pipeline(http::Pipeline); +pub struct Pipeline(http::Pipeline); -impl Pipeline { +impl Pipeline { /// Creates a new pipeline given the client library crate name and version, /// alone with user-specified and client library-specified policies. /// /// Crates can simply pass `option_env!("CARGO_PKG_NAME")` and `option_env!("CARGO_PKG_VERSION")` for the /// `crate_name` and `crate_version` arguments respectively. + /// + /// In addition, this constructor allows for specifying the response format (e.g. JSON, XML) to be used + /// when deserializing the response body. pub fn new( crate_name: Option<&'static str>, crate_version: Option<&'static str>, @@ -75,8 +78,8 @@ impl Pipeline { } // TODO: Should we instead use the newtype pattern? -impl Deref for Pipeline { - type Target = http::Pipeline; +impl Deref for Pipeline { + type Target = http::Pipeline; fn deref(&self) -> &Self::Target { &self.0 } diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs index bd76a614cc..487fccd624 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs @@ -25,6 +25,7 @@ use azure_core::{ Bytes, Result, }; use std::sync::Arc; +use typespec_client_core::http::XmlFormat; /// A client to interact with a specific Azure storage blob, although that blob may not yet exist. pub struct BlobClient { @@ -114,7 +115,7 @@ impl BlobClient { pub async fn get_properties( &self, options: Option>, - ) -> Result> { + ) -> Result> { self.client.get_properties(options).await } @@ -126,7 +127,7 @@ impl BlobClient { pub async fn set_properties( &self, options: Option>, - ) -> Result> { + ) -> Result> { self.client.set_properties(options).await } @@ -136,7 +137,7 @@ impl BlobClient { pub async fn download( &self, options: Option>, - ) -> Result> { + ) -> Result> { self.client.download(options).await } @@ -155,7 +156,7 @@ impl BlobClient { overwrite: bool, content_length: u64, options: Option>, - ) -> Result> { + ) -> Result> { let mut options = options.unwrap_or_default(); if !overwrite { @@ -179,7 +180,7 @@ impl BlobClient { pub async fn set_metadata( &self, options: Option>, - ) -> Result> { + ) -> Result> { self.client.set_metadata(options).await } @@ -191,7 +192,7 @@ impl BlobClient { pub async fn delete( &self, options: Option>, - ) -> Result> { + ) -> Result> { self.client.delete(options).await } @@ -206,7 +207,7 @@ impl BlobClient { &self, tier: AccessTier, options: Option>, - ) -> Result> { + ) -> Result> { self.client.set_tier(tier, options).await } } diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs index f66ff7a67b..44ab7c0af9 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs @@ -17,6 +17,7 @@ use azure_core::{ Result, }; use std::sync::Arc; +use typespec_client_core::http::XmlFormat; /// A client to interact with a specified Azure storage container. pub struct BlobContainerClient { @@ -99,7 +100,7 @@ impl BlobContainerClient { pub async fn create_container( &self, options: Option>, - ) -> Result> { + ) -> Result> { self.client.create(options).await } @@ -113,7 +114,7 @@ impl BlobContainerClient { pub async fn set_metadata( &self, options: Option>, - ) -> Result> { + ) -> Result> { self.client.set_metadata(options).await } @@ -125,7 +126,7 @@ impl BlobContainerClient { pub async fn delete_container( &self, options: Option>, - ) -> Result> { + ) -> Result> { self.client.delete(options).await } @@ -138,7 +139,7 @@ impl BlobContainerClient { pub async fn get_properties( &self, options: Option>, - ) -> Result> { + ) -> Result> { self.client.get_properties(options).await } } diff --git a/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs index 276f13115b..82337f0050 100644 --- a/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/block_blob_client.rs @@ -105,7 +105,7 @@ impl BlockBlobClient { &self, blocks: RequestContent, options: Option>, - ) -> Result> { + ) -> Result> { self.client.commit_block_list(blocks, options).await } @@ -124,7 +124,7 @@ impl BlockBlobClient { content_length: u64, body: RequestContent, options: Option>, - ) -> Result> { + ) -> Result> { self.client .stage_block(block_id, content_length, body, options) .await diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs index 29c089ddfd..c4af335b74 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/append_blob_client.rs @@ -21,12 +21,13 @@ use azure_core::{ Bytes, Result, }; use std::sync::Arc; +use typespec_client_core::http::XmlFormat; pub struct AppendBlobClient { pub(crate) blob_name: String, pub(crate) container_name: String, pub(crate) endpoint: Url, - pub(crate) pipeline: Pipeline, + pub(crate) pipeline: Pipeline, pub(crate) version: String, } @@ -102,7 +103,7 @@ impl AppendBlobClient { body: RequestContent, content_length: u64, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -197,7 +198,7 @@ impl AppendBlobClient { source_url: String, content_length: u64, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -312,7 +313,7 @@ impl AppendBlobClient { &self, content_length: u64, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -423,7 +424,7 @@ impl AppendBlobClient { pub async fn seal( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs index 308d9a7ea5..5ea49d4051 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs @@ -43,7 +43,7 @@ pub struct BlobClient { pub(crate) blob_name: String, pub(crate) container_name: String, pub(crate) endpoint: Url, - pub(crate) pipeline: Pipeline, + pub(crate) pipeline: Pipeline, pub(crate) version: String, } @@ -118,7 +118,7 @@ impl BlobClient { &self, copy_id: &str, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -156,7 +156,7 @@ impl BlobClient { pub async fn acquire_lease( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -214,7 +214,7 @@ impl BlobClient { pub async fn break_lease( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -271,7 +271,7 @@ impl BlobClient { &self, lease_id: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -331,7 +331,7 @@ impl BlobClient { &self, copy_source: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -442,7 +442,7 @@ impl BlobClient { pub async fn create_snapshot( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -522,7 +522,7 @@ impl BlobClient { pub async fn delete( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -586,7 +586,7 @@ impl BlobClient { pub async fn delete_immutability_policy( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -625,7 +625,7 @@ impl BlobClient { pub async fn download( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -708,7 +708,7 @@ impl BlobClient { pub async fn get_account_info( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -776,7 +776,7 @@ impl BlobClient { pub async fn get_properties( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -845,7 +845,7 @@ impl BlobClient { pub async fn get_tags( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -892,7 +892,7 @@ impl BlobClient { &self, lease_id: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -947,7 +947,7 @@ impl BlobClient { &self, lease_id: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -1001,7 +1001,7 @@ impl BlobClient { &self, expiry_options: BlobExpiryOptions, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -1036,7 +1036,7 @@ impl BlobClient { pub async fn set_immutability_policy( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -1094,7 +1094,7 @@ impl BlobClient { &self, legal_hold: bool, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -1132,7 +1132,7 @@ impl BlobClient { pub async fn set_metadata( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -1204,7 +1204,7 @@ impl BlobClient { pub async fn set_properties( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -1278,7 +1278,7 @@ impl BlobClient { &self, tags: RequestContent, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -1329,7 +1329,7 @@ impl BlobClient { &self, tier: AccessTier, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -1380,7 +1380,7 @@ impl BlobClient { &self, copy_source: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -1486,7 +1486,7 @@ impl BlobClient { pub async fn undelete( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs index 788cdd7263..4f9ccd2548 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs @@ -35,11 +35,12 @@ use azure_core::{ Result, }; use std::sync::Arc; +use typespec_client_core::http::XmlFormat; pub struct BlobContainerClient { pub(crate) container_name: String, pub(crate) endpoint: Url, - pub(crate) pipeline: Pipeline, + pub(crate) pipeline: Pipeline, pub(crate) version: String, } @@ -109,7 +110,7 @@ impl BlobContainerClient { pub async fn acquire_lease( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -156,7 +157,7 @@ impl BlobContainerClient { pub async fn break_lease( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -204,7 +205,7 @@ impl BlobContainerClient { lease_id: String, proposed_lease_id: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -247,7 +248,7 @@ impl BlobContainerClient { pub async fn create( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -293,7 +294,7 @@ impl BlobContainerClient { pub async fn delete( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -334,7 +335,7 @@ impl BlobContainerClient { pub async fn filter_blobs( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -384,7 +385,7 @@ impl BlobContainerClient { pub async fn get_access_policy( &self, options: Option>, - ) -> Result>> { + ) -> Result, XmlFormat>> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -417,7 +418,7 @@ impl BlobContainerClient { pub async fn get_account_info( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -463,7 +464,7 @@ impl BlobContainerClient { pub async fn get_properties( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -494,7 +495,7 @@ impl BlobContainerClient { pub async fn list_blob_flat_segment( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -550,7 +551,7 @@ impl BlobContainerClient { &self, delimiter: &str, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -606,7 +607,7 @@ impl BlobContainerClient { &self, lease_id: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -649,7 +650,7 @@ impl BlobContainerClient { &self, source_container_name: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -686,7 +687,7 @@ impl BlobContainerClient { &self, lease_id: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -727,7 +728,7 @@ impl BlobContainerClient { pub async fn restore( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -766,7 +767,7 @@ impl BlobContainerClient { &self, container_acl: RequestContent>, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -812,7 +813,7 @@ impl BlobContainerClient { pub async fn set_metadata( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs index f96f1fdc61..99305ea1b5 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_service_client.rs @@ -25,10 +25,11 @@ use azure_core::{ Result, }; use std::sync::Arc; +use typespec_client_core::http::XmlFormat; pub struct BlobServiceClient { pub(crate) endpoint: Url, - pub(crate) pipeline: Pipeline, + pub(crate) pipeline: Pipeline, pub(crate) version: String, } @@ -94,7 +95,7 @@ impl BlobServiceClient { pub async fn filter_blobs( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -141,7 +142,7 @@ impl BlobServiceClient { pub async fn get_account_info( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -185,7 +186,7 @@ impl BlobServiceClient { pub async fn get_properties( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -215,7 +216,7 @@ impl BlobServiceClient { pub async fn get_statistics( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -248,7 +249,7 @@ impl BlobServiceClient { start: String, expiry: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -280,7 +281,7 @@ impl BlobServiceClient { pub async fn list_containers_segment( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -328,7 +329,7 @@ impl BlobServiceClient { pub async fn set_properties( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs index 83407cc5d9..3f4190bb0f 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/block_blob_client.rs @@ -30,7 +30,7 @@ pub struct BlockBlobClient { pub(crate) blob_name: String, pub(crate) container_name: String, pub(crate) endpoint: Url, - pub(crate) pipeline: Pipeline, + pub(crate) pipeline: Pipeline, pub(crate) version: String, } @@ -109,7 +109,7 @@ impl BlockBlobClient { &self, blocks: RequestContent, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -261,7 +261,7 @@ impl BlockBlobClient { request.insert_header("x-ms-lease-id", lease_id); } request.insert_header("x-ms-version", &self.version); - self.pipeline.send_format(&ctx, &mut request).await + self.pipeline.send(&ctx, &mut request).await } /// The Put Blob from URL operation creates a new Block Blob where the contents of the blob are read from a given URL. This @@ -281,7 +281,7 @@ impl BlockBlobClient { content_length: u64, copy_source: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -423,7 +423,7 @@ impl BlockBlobClient { &self, query_request: RequestContent, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -499,7 +499,7 @@ impl BlockBlobClient { content_length: u64, body: RequestContent, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -567,7 +567,7 @@ impl BlockBlobClient { content_length: u64, source_url: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -662,7 +662,7 @@ impl BlockBlobClient { body: RequestContent, content_length: u64, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs index 02c8bb9a83..90eb670b4b 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/page_blob_client.rs @@ -26,12 +26,13 @@ use azure_core::{ Bytes, Result, }; use std::sync::Arc; +use typespec_client_core::http::XmlFormat; pub struct PageBlobClient { pub(crate) blob_name: String, pub(crate) container_name: String, pub(crate) endpoint: Url, - pub(crate) pipeline: Pipeline, + pub(crate) pipeline: Pipeline, pub(crate) version: String, } @@ -105,7 +106,7 @@ impl PageBlobClient { &self, content_length: u64, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -205,7 +206,7 @@ impl PageBlobClient { &self, copy_source: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -260,7 +261,7 @@ impl PageBlobClient { content_length: u64, blob_content_length: u64, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -380,7 +381,7 @@ impl PageBlobClient { pub async fn get_page_ranges( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -445,7 +446,7 @@ impl PageBlobClient { pub async fn get_page_ranges_diff( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -522,7 +523,7 @@ impl PageBlobClient { &self, blob_content_length: u64, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -596,7 +597,7 @@ impl PageBlobClient { &self, sequence_number_action: SequenceNumberActionType, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -664,7 +665,7 @@ impl PageBlobClient { body: RequestContent, content_length: u64, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); @@ -783,7 +784,7 @@ impl PageBlobClient { content_length: u64, range: String, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = Context::with_context(&options.method_options.context); let mut url = self.endpoint.clone(); diff --git a/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs b/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs index ac44727c08..21caf770e1 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs @@ -33,7 +33,7 @@ use azure_core::{ base64, date, http::{ headers::{HeaderName, Headers}, - Response, + Format, JsonFormat, Response, XmlFormat, }, Result, }; @@ -127,7 +127,7 @@ pub trait AppendBlobClientAppendBlockFromUrlResultHeaders: private::Sealed { } impl AppendBlobClientAppendBlockFromUrlResultHeaders - for Response + for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. @@ -203,7 +203,9 @@ pub trait AppendBlobClientAppendBlockResultHeaders: private::Sealed { fn structured_body_type(&self) -> Result>; } -impl AppendBlobClientAppendBlockResultHeaders for Response { +impl AppendBlobClientAppendBlockResultHeaders + for Response +{ /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. fn content_md5(&self) -> Result> { @@ -280,7 +282,7 @@ pub trait AppendBlobClientCreateResultHeaders: private::Sealed { fn version_id(&self) -> Result>; } -impl AppendBlobClientCreateResultHeaders for Response { +impl AppendBlobClientCreateResultHeaders for Response { /// If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the /// client can check for message content integrity. fn content_md5(&self) -> Result> { @@ -338,7 +340,7 @@ pub trait AppendBlobClientSealResultHeaders: private::Sealed { fn is_sealed(&self) -> Result>; } -impl AppendBlobClientSealResultHeaders for Response { +impl AppendBlobClientSealResultHeaders for Response { /// UTC date/time value generated by the service that indicates the time at which the response was initiated fn date(&self) -> Result> { Headers::get_optional_with(self.headers(), &DATE, |h| date::parse_rfc7231(h.as_str())) @@ -367,7 +369,9 @@ pub trait BlobClientAbortCopyFromUrlResultHeaders: private::Sealed { fn date(&self) -> Result>; } -impl BlobClientAbortCopyFromUrlResultHeaders for Response { +impl BlobClientAbortCopyFromUrlResultHeaders + for Response +{ /// UTC date/time value generated by the service that indicates the time at which the response was initiated fn date(&self) -> Result> { Headers::get_optional_with(self.headers(), &DATE, |h| date::parse_rfc7231(h.as_str())) @@ -382,7 +386,7 @@ pub trait BlobClientAcquireLeaseResultHeaders: private::Sealed { fn lease_id(&self) -> Result>; } -impl BlobClientAcquireLeaseResultHeaders for Response { +impl BlobClientAcquireLeaseResultHeaders for Response { /// UTC date/time value generated by the service that indicates the time at which the response was initiated fn date(&self) -> Result> { Headers::get_optional_with(self.headers(), &DATE, |h| date::parse_rfc7231(h.as_str())) @@ -414,7 +418,7 @@ pub trait BlobClientBreakLeaseResultHeaders: private::Sealed { fn lease_time(&self) -> Result>; } -impl BlobClientBreakLeaseResultHeaders for Response { +impl BlobClientBreakLeaseResultHeaders for Response { /// UTC date/time value generated by the service that indicates the time at which the response was initiated fn date(&self) -> Result> { Headers::get_optional_with(self.headers(), &DATE, |h| date::parse_rfc7231(h.as_str())) diff --git a/sdk/storage/azure_storage_blob_test/src/lib.rs b/sdk/storage/azure_storage_blob_test/src/lib.rs index 7338c7c57b..fbb7e480c8 100644 --- a/sdk/storage/azure_storage_blob_test/src/lib.rs +++ b/sdk/storage/azure_storage_blob_test/src/lib.rs @@ -2,7 +2,7 @@ // Licensed under the MIT License. use azure_core::{ - http::{ClientOptions, RequestContent, Response}, + http::{ClientOptions, RequestContent, Response, XmlFormat}, Result, }; use azure_core_test::Recording; @@ -92,7 +92,7 @@ pub async fn get_container_client( /// * `blob_client` - A reference to a BlobClient instance. pub async fn create_test_blob( blob_client: &BlobClient, -) -> Result> { +) -> Result> { blob_client .upload( RequestContent::from(b"hello rusty world".to_vec()), diff --git a/sdk/typespec/typespec_client_core/src/http/format.rs b/sdk/typespec/typespec_client_core/src/http/format.rs index 430e39b934..351ec13807 100644 --- a/sdk/typespec/typespec_client_core/src/http/format.rs +++ b/sdk/typespec/typespec_client_core/src/http/format.rs @@ -15,7 +15,7 @@ use crate::http::response::ResponseBody; /// This is just a marker trait, it has no methods. /// Instead, the method to actually perform the deserialization is defined in the [`DeserializeWith`] trait. /// This trait is parameterized by a type that implements the [`Format`] trait. -pub trait Format {} +pub trait Format: std::fmt::Debug {} /// A trait used to describe a type that can be deserialized using the specified [`Format`]. /// @@ -51,12 +51,14 @@ impl DeserializeWith for D { /// This format supports deserializing response bodies to: /// * [`ResponseBody`] - The raw response body, without any deserialization. /// * Any value implementing [`serde::de::DeserializeOwned`] - Deserializes the response body to the specified type using JSON deserialization. +#[derive(Debug, Clone)] pub struct JsonFormat; impl Format for JsonFormat {} /// A [`Format`] that deserializes response bodies using XML. #[cfg(feature = "xml")] +#[derive(Debug, Clone)] pub struct XmlFormat; #[cfg(feature = "xml")] diff --git a/sdk/typespec/typespec_client_core/src/http/pipeline.rs b/sdk/typespec/typespec_client_core/src/http/pipeline.rs index 921d5fabb0..97f4dd904a 100644 --- a/sdk/typespec/typespec_client_core/src/http/pipeline.rs +++ b/sdk/typespec/typespec_client_core/src/http/pipeline.rs @@ -7,7 +7,7 @@ use crate::http::{ }; use std::sync::Arc; -use super::JsonFormat; +use super::{Format, JsonFormat}; /// Execution pipeline. /// @@ -32,13 +32,17 @@ use super::JsonFormat; /// cannot be enforced by code). All policies except Transport policy can assume there is another following policy (so /// `self.pipeline[0]` is always valid). #[derive(Debug, Clone)] -pub struct Pipeline { +pub struct Pipeline { pipeline: Vec>, + _phantom: std::marker::PhantomData, } -impl Pipeline { +impl Pipeline { /// Creates a new pipeline given the client library crate name and version, - /// alone with user-specified and client library-specified policies. + /// along with user-specified and client library-specified policies. + /// + /// In addition, this constructor allows for specifying the response format (e.g. JSON, XML) to be used + /// when deserializing the response body. pub fn new( options: ClientOptions, per_call_policies: Vec>, @@ -69,7 +73,10 @@ impl Pipeline { pipeline.push(transport); - Self { pipeline } + Self { + pipeline, + _phantom: std::marker::PhantomData, + } } pub fn replace_policy(&mut self, policy: Arc, position: usize) -> Arc { @@ -84,20 +91,12 @@ impl Pipeline { &self, ctx: &Context<'_>, request: &mut Request, - ) -> crate::Result> { + ) -> crate::Result> { self.pipeline[0] .send(ctx, request, &self.pipeline[1..]) .await .map(|r| r.with_model_type()) } - - pub async fn send_format( - &self, - ctx: &Context<'_>, - request: &mut Request, - ) -> crate::Result> { - self.send(ctx, request).await.map(|r| r.with_format()) - } } #[cfg(test)] @@ -143,7 +142,7 @@ mod tests { transport: Some(TransportOptions::new_custom_policy(Arc::new(Responder {}))), ..Default::default() }; - let pipeline = Pipeline::new(options, Vec::new(), Vec::new()); + let pipeline: Pipeline = Pipeline::new(options, Vec::new(), Vec::new()); let mut request = Request::new("http://localhost".parse().unwrap(), Method::Get); pipeline.send(&Context::default(), &mut request).await }