Skip to content

Commit 4d6f02a

Browse files
bmc-msftdemoray
andauthored
move storage_blob operations to follow the into_future pattern (#838)
* move storage_blob operations to follow the into_future pattern Changes beyond the into_future pattern updates: 1. This updates ContentDisposition, ContentEncoding, ContentLanguage, and ContentType to follow other header types. 2. This adds a `BlobClient.get_content` helper that iterates over `BlobClient.get().stream()` and writes the data into a single Vec, returning the Vec. This was an extremely common pattern in the examples and something akin to it is available in most of the other SDKs as well. TODO: * move container operations to the into_future model * fmt * finish moving from .execute() to .into_future() * fmt * add IntoFuture impls * update tests & examples * move back to original implementation * address feedback * fmt * make pub * make pub * address feedback * remove debug/trace from runtime per discussion * fmt * address clippy * more consistent formatting of response_from_headers uses * address feedback * remove useless .into() Co-authored-by: Brian Caswell <[email protected]>
1 parent ff8f954 commit 4d6f02a

File tree

150 files changed

+3969
-3633
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

150 files changed

+3969
-3633
lines changed
Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,42 @@
11
use crate::headers::{self, Header};
22

3-
#[derive(Debug, Clone, Copy)]
4-
pub struct ContentDisposition<'a>(&'a str);
5-
6-
impl<'a, S> From<S> for ContentDisposition<'a>
7-
where
8-
S: Into<&'a str>,
9-
{
10-
fn from(s: S) -> Self {
11-
Self(s.into())
3+
#[derive(Clone, Debug, PartialEq, Eq)]
4+
pub struct ContentDisposition(std::borrow::Cow<'static, str>);
5+
6+
impl ContentDisposition {
7+
pub fn as_str(&self) -> &str {
8+
self.0.as_ref()
9+
}
10+
11+
pub const fn from_static(s: &'static str) -> Self {
12+
Self(std::borrow::Cow::Borrowed(s))
13+
}
14+
}
15+
16+
impl From<&'static str> for ContentDisposition {
17+
fn from(s: &'static str) -> Self {
18+
Self::from_static(s)
19+
}
20+
}
21+
22+
impl From<String> for ContentDisposition {
23+
fn from(s: String) -> Self {
24+
Self(std::borrow::Cow::Owned(s))
25+
}
26+
}
27+
28+
impl From<&String> for ContentDisposition {
29+
fn from(s: &String) -> Self {
30+
Self(std::borrow::Cow::Owned(s.clone()))
1231
}
1332
}
1433

15-
impl<'a> Header for ContentDisposition<'a> {
34+
impl Header for ContentDisposition {
1635
fn name(&self) -> headers::HeaderName {
17-
http::header::CONTENT_DISPOSITION.into()
36+
http::header::CONTENT_TYPE.into()
1837
}
1938

2039
fn value(&self) -> headers::HeaderValue {
21-
self.0.to_owned().into()
40+
self.0.to_string().into()
2241
}
2342
}
Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,42 @@
11
use crate::headers::{self, Header};
22

3-
#[derive(Debug, Clone, Copy)]
4-
pub struct ContentEncoding<'a>(&'a str);
5-
6-
impl<'a, S> From<S> for ContentEncoding<'a>
7-
where
8-
S: Into<&'a str>,
9-
{
10-
fn from(s: S) -> Self {
11-
Self(s.into())
3+
#[derive(Clone, Debug, PartialEq, Eq)]
4+
pub struct ContentEncoding(std::borrow::Cow<'static, str>);
5+
6+
impl ContentEncoding {
7+
pub fn as_str(&self) -> &str {
8+
self.0.as_ref()
9+
}
10+
11+
pub const fn from_static(s: &'static str) -> Self {
12+
Self(std::borrow::Cow::Borrowed(s))
13+
}
14+
}
15+
16+
impl From<&'static str> for ContentEncoding {
17+
fn from(s: &'static str) -> Self {
18+
Self::from_static(s)
19+
}
20+
}
21+
22+
impl From<String> for ContentEncoding {
23+
fn from(s: String) -> Self {
24+
Self(std::borrow::Cow::Owned(s))
25+
}
26+
}
27+
28+
impl From<&String> for ContentEncoding {
29+
fn from(s: &String) -> Self {
30+
Self(std::borrow::Cow::Owned(s.clone()))
1231
}
1332
}
1433

15-
impl<'a> Header for ContentEncoding<'a> {
34+
impl Header for ContentEncoding {
1635
fn name(&self) -> headers::HeaderName {
17-
http::header::CONTENT_ENCODING.into()
36+
http::header::CONTENT_TYPE.into()
1837
}
1938

2039
fn value(&self) -> headers::HeaderValue {
21-
self.0.to_owned().into()
40+
self.0.to_string().into()
2241
}
2342
}
Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,42 @@
11
use crate::headers::{self, Header};
22

3-
#[derive(Debug, Clone, Copy)]
4-
pub struct ContentLanguage<'a>(&'a str);
5-
6-
impl<'a, S> From<S> for ContentLanguage<'a>
7-
where
8-
S: Into<&'a str>,
9-
{
10-
fn from(s: S) -> Self {
11-
Self(s.into())
3+
#[derive(Clone, Debug, PartialEq, Eq)]
4+
pub struct ContentLanguage(std::borrow::Cow<'static, str>);
5+
6+
impl ContentLanguage {
7+
pub fn as_str(&self) -> &str {
8+
self.0.as_ref()
9+
}
10+
11+
pub const fn from_static(s: &'static str) -> Self {
12+
Self(std::borrow::Cow::Borrowed(s))
13+
}
14+
}
15+
16+
impl From<&'static str> for ContentLanguage {
17+
fn from(s: &'static str) -> Self {
18+
Self::from_static(s)
19+
}
20+
}
21+
22+
impl From<String> for ContentLanguage {
23+
fn from(s: String) -> Self {
24+
Self(std::borrow::Cow::Owned(s))
25+
}
26+
}
27+
28+
impl From<&String> for ContentLanguage {
29+
fn from(s: &String) -> Self {
30+
Self(std::borrow::Cow::Owned(s.clone()))
1231
}
1332
}
1433

15-
impl<'a> Header for ContentLanguage<'a> {
34+
impl Header for ContentLanguage {
1635
fn name(&self) -> headers::HeaderName {
17-
http::header::CONTENT_LANGUAGE.into()
36+
http::header::CONTENT_TYPE.into()
1837
}
1938

2039
fn value(&self) -> headers::HeaderValue {
21-
self.0.to_owned().into()
40+
self.0.to_string().into()
2241
}
2342
}
Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,44 @@
11
use crate::headers::{self, Header};
22

3-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4-
pub struct ContentType<'a>(&'a str);
3+
#[derive(Clone, Debug, PartialEq, Eq)]
4+
pub struct ContentType(std::borrow::Cow<'static, str>);
55

6-
impl<'a> ContentType<'a> {
7-
pub fn new(s: &'a str) -> Self {
8-
Self(s)
6+
impl ContentType {
7+
pub fn as_str(&self) -> &str {
8+
self.0.as_ref()
99
}
10+
}
1011

11-
pub fn as_str(&self) -> &str {
12-
self.0
12+
impl From<&'static str> for ContentType {
13+
fn from(s: &'static str) -> Self {
14+
Self(std::borrow::Cow::Borrowed(s))
15+
}
16+
}
17+
18+
impl From<String> for ContentType {
19+
fn from(s: String) -> Self {
20+
Self(std::borrow::Cow::Owned(s))
21+
}
22+
}
23+
24+
impl From<&String> for ContentType {
25+
fn from(s: &String) -> Self {
26+
Self(std::borrow::Cow::Owned(s.clone()))
1327
}
1428
}
1529

16-
impl<'a, S> From<S> for ContentType<'a>
17-
where
18-
S: Into<&'a str>,
19-
{
20-
fn from(s: S) -> Self {
21-
Self(s.into())
30+
impl ContentType {
31+
pub fn new(s: impl Into<ContentType>) -> Self {
32+
s.into()
2233
}
2334
}
2435

25-
impl<'a> Header for ContentType<'a> {
36+
impl<'a> Header for ContentType {
2637
fn name(&self) -> headers::HeaderName {
2738
http::header::CONTENT_TYPE.into()
2839
}
2940

3041
fn value(&self) -> headers::HeaderValue {
31-
self.0.to_owned().into()
42+
self.0.to_string().into()
3243
}
3344
}
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
use crate::AppendToUrlQuery;
22

33
#[derive(Debug, Clone)]
4-
pub struct Delimiter<'a>(&'a str);
4+
pub struct Delimiter(String);
55

6-
impl<'a> Delimiter<'a> {
7-
pub fn new(delimiter: &'a str) -> Self {
8-
Self(delimiter)
6+
impl AppendToUrlQuery for Delimiter {
7+
fn append_to_url_query(&self, url: &mut url::Url) {
8+
url.query_pairs_mut()
9+
.append_pair("delimiter", self.0.as_ref());
910
}
1011
}
1112

12-
impl<'a> AppendToUrlQuery for Delimiter<'a> {
13-
fn append_to_url_query(&self, url: &mut url::Url) {
14-
url.query_pairs_mut().append_pair("delimiter", self.0);
13+
impl From<&str> for Delimiter {
14+
fn from(delimiter: &str) -> Self {
15+
Self(delimiter.into())
1516
}
1617
}
1718

18-
impl<'a> From<&'a str> for Delimiter<'a> {
19-
fn from(delimiter: &'a str) -> Self {
19+
impl From<String> for Delimiter {
20+
fn from(delimiter: String) -> Self {
2021
Self(delimiter)
2122
}
2223
}

sdk/storage_blobs/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ enable_reqwest_rustls = [
4848
"azure_core/enable_reqwest_rustls",
4949
"azure_storage/enable_reqwest_rustls",
5050
]
51+
into_future = []

sdk/storage_blobs/examples/blob_00.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
#[macro_use]
22
extern crate log;
3-
use azure_core::{
4-
error::{ErrorKind, ResultExt},
5-
prelude::*,
6-
};
3+
use azure_core::error::{ErrorKind, ResultExt};
74
use azure_storage::core::prelude::*;
85
use azure_storage_blobs::prelude::*;
9-
use futures::stream::StreamExt;
6+
use futures::StreamExt;
107

118
#[tokio::main]
129
async fn main() -> azure_core::Result<()> {
@@ -40,23 +37,21 @@ async fn main() -> azure_core::Result<()> {
4037

4138
// this is a single call that retrieves the first 1KB of the blob (or less if the blob is
4239
// smaller). The range(...) call is optional.
43-
let response = blob_client
44-
.get()
45-
.range(Range::new(0, 1024))
46-
.execute()
47-
.await?;
40+
let response = Box::pin(blob_client.get().range(0u64..1024).stream(1024))
41+
.next()
42+
.await
43+
.expect("stream failed")?;
4844

4945
println!("{:#?}", response);
5046

51-
let mut complete_response = Vec::new();
52-
47+
let mut complete_response = vec![];
5348
// this is how you stream a blob. You can specify the range(...) value as above if necessary.
5449
// In this case we are retrieving the whole blob in 8KB chunks.
5550
let mut stream = Box::pin(blob_client.get().stream(1024 * 8));
5651
while let Some(value) = stream.next().await {
5752
let data = value?.data;
5853
println!("received {:?} bytes", data.len());
59-
complete_response.extend(&data as &[u8]);
54+
complete_response.extend(&data);
6055
}
6156

6257
let s_content = String::from_utf8(complete_response).map_kind(ErrorKind::DataConversion)?;

sdk/storage_blobs/examples/blob_01.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use azure_storage::core::prelude::*;
22
use azure_storage_blobs::prelude::*;
3+
use futures::StreamExt;
34

45
#[tokio::main]
56
async fn main() -> azure_core::Result<()> {
@@ -22,18 +23,11 @@ async fn main() -> azure_core::Result<()> {
2223
let container_client = storage_client.as_container_client(&container_name);
2324
let blob_client = container_client.as_blob_client("SorgeniaReorganizeRebuildIndexes.zip");
2425

25-
let _res = container_client
26-
.list_blobs()
27-
.include_copy(true)
28-
.include_deleted(true)
29-
.include_metadata(true)
30-
.include_snapshots(true)
31-
.include_uncommitted_blobs(true)
32-
.execute()
33-
.await?;
34-
35-
let result = blob_client.get().execute().await?;
36-
26+
// only get the first 8k chunk
27+
let result = Box::pin(blob_client.get().stream(1024 * 8))
28+
.next()
29+
.await
30+
.expect("stream failed")?;
3731
println!("{:?}", result);
3832

3933
Ok(())

sdk/storage_blobs/examples/blob_02_bearer_token.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#[macro_use]
22
extern crate log;
33

4-
use azure_core::error::{ErrorKind, ResultExt};
54
use azure_storage::core::prelude::*;
65
use azure_storage_blobs::prelude::*;
76

@@ -30,12 +29,8 @@ async fn main() -> azure_core::Result<()> {
3029

3130
trace!("Requesting blob");
3231

33-
let response = blob_client.get().execute().await?;
34-
35-
let s_content =
36-
String::from_utf8(response.data.to_vec()).map_kind(ErrorKind::DataConversion)?;
37-
println!("blob == {:?}", blob);
38-
println!("s_content == {}", s_content);
32+
let blob = blob_client.get_content().await?;
33+
println!("response == {:?}", blob);
3934

4035
Ok(())
4136
}

sdk/storage_blobs/examples/blob_04.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ async fn main() -> azure_core::Result<()> {
4242

4343
let block_id = Bytes::from(format!("{}", i));
4444
block_ids.push(block_id.clone());
45-
let hash = md5::compute(slice.clone()).into();
45+
let hash = md5::compute(slice.clone());
4646

4747
let put_block_response = blob_client
4848
.put_block(block_id, slice)
49-
.hash(&hash)
50-
.execute()
49+
.hash(hash)
50+
.into_future()
5151
.await?;
5252

5353
println!("put_block_response == {:#?}", put_block_response);
@@ -59,16 +59,15 @@ async fn main() -> azure_core::Result<()> {
5959
}
6060

6161
let res = blob_client
62-
.put_block_list(&block_list)
62+
.put_block_list(block_list)
6363
.content_md5(md5::compute(data))
64-
.execute()
64+
.into_future()
6565
.await?;
6666
println!("PutBlockList == {:?}", res);
6767

68-
let retrieved_blob = blob_client.get().execute().await?;
69-
println!("retrieved_blob == {:?}", retrieved_blob);
68+
let blob = blob_client.get_content().await?;
7069

71-
let s = String::from_utf8(retrieved_blob.data.to_vec()).map_kind(ErrorKind::DataConversion)?;
70+
let s = String::from_utf8(blob).map_kind(ErrorKind::DataConversion)?;
7271
println!("retrieved contents == {}", s);
7372

7473
Ok(())

0 commit comments

Comments
 (0)