@@ -5,11 +5,11 @@ pub use crate::generated::clients::{BlobClient, BlobClientOptions};
55
66use crate :: {
77 generated:: clients:: BlobClient as GeneratedBlobClient ,
8+ generated:: models:: BlobClientDownloadInternalOptions ,
89 logging:: apply_storage_logging_defaults,
910 models:: {
10- http_ranges:: IntoRangeHeader , method_options:: BlobClientManagedDownloadOptions ,
11- BlobClientDownloadOptions , BlobClientDownloadResult , BlobClientUploadOptions ,
12- BlobClientUploadResult , StorageErrorCode ,
11+ http_ranges:: IntoRangeHeader , BlobClientDownloadOptions , BlobClientDownloadResult ,
12+ BlobClientUploadOptions , BlobClientUploadResult , StorageErrorCode ,
1313 } ,
1414 partitioned_transfer:: { self , PartitionedDownloadBehavior } ,
1515 pipeline:: StorageHeadersPolicy ,
@@ -21,13 +21,12 @@ use azure_core::{
2121 error:: ErrorKind ,
2222 http:: {
2323 policies:: { auth:: BearerTokenAuthorizationPolicy , Policy } ,
24- response :: { AsyncResponse , PinnedStream } ,
25- AsyncRawResponse , NoFormat , Pipeline , RequestContent , StatusCode , Url , UrlExt ,
24+ AsyncRawResponse , ClientMethodOptions , NoFormat , Pipeline , RequestContent , StatusCode , Url ,
25+ UrlExt ,
2626 } ,
2727 tracing, Bytes , Result ,
2828} ;
29- use std:: sync:: Arc ;
30- use std:: { num:: NonZero , ops:: Range } ;
29+ use std:: { num:: NonZero , ops:: Range , sync:: Arc } ;
3130
3231impl BlobClient {
3332 /// Creates a new BlobClient, using Entra ID authentication.
@@ -113,67 +112,27 @@ impl BlobClient {
113112 } )
114113 }
115114
116- /// The managed download operation retrieves the content of an existing blob .
115+ /// Downloads a blob directly into a caller-provided buffer .
117116 ///
118- /// # Arguments
119- ///
120- /// * `options` - Optional parameters for the request.
121- pub async fn managed_download (
122- & self ,
123- options : Option < BlobClientManagedDownloadOptions < ' _ > > ,
124- ) -> Result < PinnedStream > {
125- let options = options. unwrap_or_default ( ) ;
126- let parallel = options. parallel . unwrap_or ( DEFAULT_PARALLEL ) ;
127- let partition_size = options. partition_size . unwrap_or ( DEFAULT_PARTITION_SIZE ) ;
128- // construct exhaustively to ensure we catch new options when added
129- let get_range_options = BlobClientDownloadOptions {
130- encryption_algorithm : options. encryption_algorithm ,
131- encryption_key : options. encryption_key ,
132- encryption_key_sha256 : options. encryption_key_sha256 ,
133- if_match : options. if_match ,
134- if_modified_since : options. if_modified_since ,
135- if_none_match : options. if_none_match ,
136- if_tags : options. if_tags ,
137- if_unmodified_since : options. if_unmodified_since ,
138- lease_id : options. lease_id ,
139- // TODO: method_options: options.method_options,
140- range : None ,
141- range_get_content_crc64 : options. range_get_content_crc64 ,
142- range_get_content_md5 : options. range_get_content_md5 ,
143- snapshot : options. snapshot ,
144- structured_body_type : options. structured_body_type ,
145- timeout : options. timeout ,
146- version_id : options. version_id ,
147- ..Default :: default ( )
148- } ;
149-
150- let client = GeneratedBlobClient {
151- endpoint : self . endpoint . clone ( ) ,
152- pipeline : self . pipeline . clone ( ) ,
153- version : self . version . clone ( ) ,
154- tracer : self . tracer . clone ( ) ,
155- } ;
156- let client = BlobClientDownloadBehavior :: new ( client, get_range_options) ;
157-
158- partitioned_transfer:: download ( options. range , parallel, partition_size, Arc :: new ( client) )
159- . await
160- }
161-
162- /// The managed download operation retrieves the content of an existing blob.
117+ /// Unlike [`BlobClient::download`], which allocates and returns the blob data, this method
118+ /// writes the content directly into `buffer`. The blob is fetched in parallel range requests and assembled in-place.
163119 ///
164120 /// # Arguments
165121 ///
122+ /// * `buffer` - The buffer to write the blob content into. Must be large enough to hold the requested range or the entire blob.
166123 /// * `options` - Optional parameters for the request.
167- pub async fn managed_download_into (
124+ pub async fn download_into (
168125 & self ,
169126 buffer : & mut [ u8 ] ,
170- options : Option < BlobClientManagedDownloadOptions < ' _ > > ,
127+ options : Option < BlobClientDownloadOptions < ' _ > > ,
171128 ) -> Result < usize > {
172129 let options = options. unwrap_or_default ( ) ;
173- let parallel = options. parallel . unwrap_or ( DEFAULT_PARALLEL ) ;
174- let partition_size = options. partition_size . unwrap_or ( DEFAULT_PARTITION_SIZE ) ;
175- // construct exhaustively to ensure we catch new options when added
176- let get_range_options = BlobClientDownloadOptions {
130+ let parallel = options. parallel . unwrap_or ( DEFAULT_DOWNLOAD_PARALLEL ) ;
131+ let partition_size = options
132+ . partition_size
133+ . unwrap_or ( DEFAULT_DOWNLOAD_PARTITION_SIZE ) ;
134+ // Construct exhaustively to catch new options.
135+ let get_range_options = BlobClientDownloadInternalOptions {
177136 encryption_algorithm : options. encryption_algorithm ,
178137 encryption_key : options. encryption_key ,
179138 encryption_key_sha256 : options. encryption_key_sha256 ,
@@ -183,15 +142,16 @@ impl BlobClient {
183142 if_tags : options. if_tags ,
184143 if_unmodified_since : options. if_unmodified_since ,
185144 lease_id : options. lease_id ,
186- // TODO: method_options: options.method_options,
145+ method_options : ClientMethodOptions {
146+ context : options. method_options . context . into_owned ( ) ,
147+ } ,
187148 range : None ,
188149 range_get_content_crc64 : options. range_get_content_crc64 ,
189150 range_get_content_md5 : options. range_get_content_md5 ,
190151 snapshot : options. snapshot ,
191152 structured_body_type : options. structured_body_type ,
192153 timeout : options. timeout ,
193154 version_id : options. version_id ,
194- ..Default :: default ( )
195155 } ;
196156
197157 let client = GeneratedBlobClient {
@@ -289,14 +249,65 @@ impl BlobClient {
289249 } )
290250 }
291251
292- /// Downloads a blob from the service, including its metadata and properties.
252+ /// Downloads a blob and its contents from the service.
253+ ///
254+ /// This operation performs a managed (multi-part) download, splitting the blob into
255+ /// parallel range requests for better performance on large blobs. The returned
256+ /// [`BlobClientDownloadResult::body`] contains the complete blob data, while
257+ /// [`BlobClientDownloadResult::properties`] and /// [`BlobClientDownloadResult::headers`]
258+ /// reflect only the initial response's metadata and properties.
259+ ///
260+ /// # Arguments
293261 ///
294262 /// * `options` - Optional configuration for the request.
263+ #[ tracing:: function( "Storage.Blob.Blob.download" ) ]
295264 pub async fn download (
296265 & self ,
297266 options : Option < BlobClientDownloadOptions < ' _ > > ,
298- ) -> Result < AsyncResponse < BlobClientDownloadResult > > {
299- self . download_internal ( options) . await
267+ ) -> Result < BlobClientDownloadResult > {
268+ let options = options. unwrap_or_default ( ) ;
269+ let parallel = options. parallel . unwrap_or ( DEFAULT_DOWNLOAD_PARALLEL ) ;
270+ let partition_size = options
271+ . partition_size
272+ . unwrap_or ( DEFAULT_DOWNLOAD_PARTITION_SIZE ) ;
273+ // Construct exhaustively to catch new options.
274+ let get_range_options = BlobClientDownloadInternalOptions {
275+ encryption_algorithm : options. encryption_algorithm ,
276+ encryption_key : options. encryption_key ,
277+ encryption_key_sha256 : options. encryption_key_sha256 ,
278+ if_match : options. if_match ,
279+ if_modified_since : options. if_modified_since ,
280+ if_none_match : options. if_none_match ,
281+ if_tags : options. if_tags ,
282+ if_unmodified_since : options. if_unmodified_since ,
283+ lease_id : options. lease_id ,
284+ // requires into_owned due to BlobClientDownloadBehavior w/ 'static Behavior
285+ method_options : ClientMethodOptions {
286+ context : options. method_options . context . into_owned ( ) ,
287+ } ,
288+ range : None ,
289+ range_get_content_crc64 : options. range_get_content_crc64 ,
290+ range_get_content_md5 : options. range_get_content_md5 ,
291+ snapshot : options. snapshot ,
292+ structured_body_type : options. structured_body_type ,
293+ timeout : options. timeout ,
294+ version_id : options. version_id ,
295+ } ;
296+ let inner_client = GeneratedBlobClient {
297+ endpoint : self . endpoint . clone ( ) ,
298+ pipeline : self . pipeline . clone ( ) ,
299+ version : self . version . clone ( ) ,
300+ tracer : self . tracer . clone ( ) ,
301+ } ;
302+ let behavior = BlobClientDownloadBehavior :: new ( inner_client, get_range_options) ;
303+ let response = partitioned_transfer:: download (
304+ options. range ,
305+ parallel,
306+ partition_size,
307+ Arc :: new ( behavior) ,
308+ )
309+ . await ?;
310+ BlobClientDownloadResult :: from_headers ( response)
300311 }
301312
302313 /// Uploads content to a block blob, overwriting any existing blob by default.
@@ -340,15 +351,16 @@ impl BlobClient {
340351}
341352
342353// unwrap evaluated at compile time
343- const DEFAULT_PARALLEL : NonZero < usize > = NonZero :: new ( 4 ) . unwrap ( ) ;
344- const DEFAULT_PARTITION_SIZE : NonZero < usize > = NonZero :: new ( 4 * 1024 * 1024 ) . unwrap ( ) ;
354+ const DEFAULT_DOWNLOAD_PARALLEL : NonZero < usize > = NonZero :: new ( 4 ) . unwrap ( ) ;
355+ const DEFAULT_DOWNLOAD_PARTITION_SIZE : NonZero < usize > = NonZero :: new ( 4 * 1024 * 1024 ) . unwrap ( ) ;
345356
346357struct BlobClientDownloadBehavior < ' a > {
347358 client : GeneratedBlobClient ,
348- options : BlobClientDownloadOptions < ' a > ,
359+ options : BlobClientDownloadInternalOptions < ' a > ,
349360}
361+
350362impl < ' a > BlobClientDownloadBehavior < ' a > {
351- fn new ( client : GeneratedBlobClient , options : BlobClientDownloadOptions < ' a > ) -> Self {
363+ fn new ( client : GeneratedBlobClient , options : BlobClientDownloadInternalOptions < ' a > ) -> Self {
352364 Self { client, options }
353365 }
354366}
0 commit comments